Binary XML file line #21: Error inflating class fragment - android

I have a map fragment class and I added a button on top of it. When I click on it I am calling another fragment class with a simple textview and save button. When save is clicked I want to go back to my mapfragment class. Right now it is throwing an error when I click save and go back. The error is when it is inflating the class > Just wondering if I am doing anything wrong while popping from the backstack. I just want to remove the last one and go back to my map.
My map layout is as follows:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
</fragment>
</LinearLayout>
MapFragment is as follows:
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.maplayout,container,false);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getChildFragmentManager();
fragment = (MapFragment) fm.findFragmentById(R.id.map);
if (fragment == null) {
fragment = MapFragment.newInstance();
fm.beginTransaction().replace(R.id.map, fragment).commit();
}
}
The back method:
FragmentManager fm = getActivity().getFragmentManager();
fm.popBackStack("TEXT_FRAGMENT", FragmentManager.POP_BACK_STACK_INCLUSIVE);
fm.beginTransaction()
.replace(R.id.map_tab,
mapFragment,
"maptab")
.addToBackStack("maptab")
.commit();
The error is: Fragment does not have a view.
The map_tab is the tab on which MapFragment was added. The map fragment is added on top of this.
EDIT: In the back method I added fm.popBackStack("TEXT_FRAGMENT", FragmentManager.POP_BACK_STACK_INCLUSIVE
but then this gives me the error when I go back to my Map Fragment and on inflating I get the error.

Don't commit a new Fragment. Instead,
Look at the getFragmentManager().popBackStack() methods (there are several to choose from)
http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()

Got it to work finally. Had to remove the mapfragment before adding a new fragment.

Related

When navigating from one fragment to another, the second fragment overlaps

On the click of a button I want to navigate from one fragment to another. The problem is that when I press the button the second fragment overlaps the other.
I searched for some answers but it doesn't seem to word in my case. I tried adding a background color but it still overlaps.
So after I click the button the following thing happens:
Here are my codes:
I gave the first fragment an ID:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment"
android:background="#FFF">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="1dip"
app:layout_constraintBottom_toTopOf="parent"
android:background="#FFF"/>
The ID of the button is: nextFragment
The code inside the class of the first fragment is:
nextFragment = v.findViewById(R.id.nextFragment);
nextFragment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v){
Fragment fragment = new NotificationsFragment();
FragmentManager fragmentManager = getParentFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
}
});
Hope i gave enough information, if not don't hesitate to ask for more! Thanks in advance.
The problem is that you are using fragment_container as the first fragment instead of the container for your first fragment.
In your MainActivity you have to load your first fragment inside that container. Not use it as a fragment.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
Fragment firstFragment = new YourFirstFragment();
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, firstFragment);
transaction.commit();
}
}
After that, in your first fragment, when you will replace the fragment it will work great.
So the solution was simple.. I gave an Id to a framelayout inside the first fragment instead of to the root layout.
Now the next thing is that the tab on the bottom also has to change when the button is pressed.

How to use PlaceAutoCompleteFragment widget in a Fragment

I am using PlaceAutoCompleteFragment inside a Fragment. First time when Fragment(App fragment in which PlaceAutoCompleteFragment is placed) opens it works fine like a charm.
But, then second time I hit button to open Fragment it crashes with below error. It works only a single time.
FATAL EXCEPTION:
android.view.InflateException: Binary XML file line #64: Error
inflating class fragment Caused by:
java.lang.IllegalArgumentException: Binary XML file line #64:
Duplicate id 0x7f0d0094, tag null, or parent id 0xffffffff with
another fragment for
com.google.android.gms.location.places.ui.PlaceAutocompleteFragment
This is how I am using this,for Search location
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.parkingview_fragment, container, false);
mapFragment = (SupportMapFragment) this.getChildFragmentManager().findFragmentById(R.id.map_parkingview);
mapFragment.getMapAsync(this);
// For Search location
PlaceAutocompleteFragment autocompleteFragment = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
autocompleteFragment = (PlaceAutocompleteFragment) getActivity().getFragmentManager().findFragmentById(R.id.place_fragment_parkingview);
}
autocompleteFragment.setOnPlaceSelectedListener(this);
autocompleteFragment.setHint("Search a Location");
// autocompleteFragment.setBoundsBias(BOUNDS_MOUNTAIN_VIEW);
return view;
}
XML:
<fragment
android:id="#+id/place_fragment_parkingview"
android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Declare your fragment Dynamically it will solve the issue.
<FrameLayout
android:id="#+id/fragment_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
And Update your fragment onCreateView
SupportPlaceAutocompleteFragment autocompleteFragment = new SupportPlaceAutocompleteFragment();
android.support.v4.app.FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_content, autocompleteFragment);
ft.commit();
This problem is caused because you haven't removed yet the PlaceAutoCompleteFragment instance created before at some point.
Careful guys! If you use the method posted by Jordon, it will work, but the fragment's views (the input edittext, and the clearbutton for example) won't be accesible because the fragment's views aren't created yet...the correct answer is REMOVE the instance of the fragment putted in the xml file, programmatically, overwriting the onDestroyView method on the Fragment containing the PlaceAutoCompleteFragment.
#Override
public void onDestroyView() {
if (autocompleteFragment != null) {
android.support.v4.app.FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.remove(autocompleteFragment).commitNowAllowingStateLoss();
}
super.onDestroyView();
}
This way, anytime you recreate your Fragment it won't have an instance of the PlaceAutoCompleteFragment already created. Happy Coding!
I was using-
<fragment
android:id="#+id/location_autocomplete_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/plain_border"
android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment" />
inside my fragment layout file and initializing it using-
PlaceAutocompleteFragment locationAutocompleteFragment = (PlaceAutocompleteFragment)
getActivity().getFragmentManager()
.findFragmentById(R.id.location_autocomplete_fragment);
I switched to-
<fragment
android:id="#+id/location_autocomplete_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/plain_border"
android:name="com.google.android.gms.location.places.ui.SupportPlaceAutocompleteFragment" />
and initialisation by-
SupportPlaceAutocompleteFragment locationAutocompleteFragment = (SupportPlaceAutocompleteFragment)
getChildFragmentManager()
.findFragmentById(R.id.location_autocomplete_fragment);

Replaced fragment still visible behind new fragment

I try to implement an activity which can load different fragments into one container view element. I follow the Building a Flexible UI Training. Problem: When replacing a fragment, I can still see the replaced fragment in the background.
I see that my question has already been asked numerous times. However all the answers I found seem to be just a workaround (setting the background-color of fragments) or do not apply.
Here is what I have setup so far:
The activity's XML layout contains one FrameLayout as a container for the fragments:
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
The id fragment_container is used nowhere else in the project.
The complete XML layout of the first fragment:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="First Fragment" />
The complete XML layout of the second fragment:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#ff0000"
android:text="Fragment Second" />
The class file of the first fragment looks like this (class for second fragment analogous):
public class FirstFragment extends Fragment {
public FirstFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
In the activity's onCreate method I load the first fragment:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// load first fragment
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, new FirstFragment())
.commit();
}
}
When selecting a menu item I try to replace the first fragment with the second fragment with this code in the activity's onOptionsItemSelected method:
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, new SecondFragment())
.addToBackStack(null) // <-- does not make any difference if left out
.commit();
The result is that the text "Fragment Second" is printed in red above the text "First Fragment".
What is the "right way" (i.e. not just setting a background-color) to fix this problem?
I noticed this in onCreate:
getSupportFragmentManager()
and this in onOptionsItemSelected:
getFragmentManager()
There are actually both versions of the FragmentManager in AppCompatActivity and they know nothing about each other. So when you tell android.app.FragmentManager to replace a fragment that was added by android.support.v4.app.FragmentManager, it doesn't know anything about a FirstFragment so the operation acts more like an add than a replace.
I've made this mistake more than once. You'll need to comb through your code and make sure you are consistent about using the support class vs. the regular class.

Naviagation Drawer Stuck with Fragments Injection

I am trying to add to the navigation drawer using fragments as follows using the onNavigationDrawerItemSelected But the compiler is giving me a incomparable type I do not no how I am new to Andriod I used the NaviagationDrwaer Template app to give me heads start.
I am hopeing someone can point me in the right direction with this been driving me nuts. Also any ideas with this apporach how one would handle icons in the menu ?.
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment;
switch(position){
case 0:
fragment = new HomeFragment(); --- This line is where the error comes
break;
}
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager()
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
My HomeFragment Class Conists Of
public class HomeFragment extends Fragment {
View rootview;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootview = inflater.inflate(R.layout.home_layout, container, false);
return rootview;
}
}
And my home_layout file as follows
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="com.example.davidbuckley.cautioapp.home">
<!-- TODO: Update blank fragment layout -->
<TextView android:layout_width="match_parent" android:layout_height="match_parent"
android:text="#string/hello_blank_fragment" />
</RelativeLayout>
One of your fragments is probably a 'support' Fragment: http://developer.android.com/reference/android/support/v4/app/Fragment.html
While the other is probably a native Fragment: http://developer.android.com/reference/android/app/Fragment.html

Fragment duplication on Fragment Transaction

Ok, whenever I try to replace a fragment in my application, it only adds the fragment inside of the container the other fragment is, and leaves the current fragment. I've tried calling replace and referencing the view the contains the fragment, and by referencing the fragment itself. Neither of these work. I can add a fragment to a view with the fragment transaction manager, but even if I try to remove it after its been added, it doesn't work. Any help would be appreciated. Here are my files.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Setup the actionabar. Use setDrawableBackground to set a background image for the actionbar.
final ActionBar actionbar = getActionBar();
actionbar.setDisplayShowTitleEnabled(false);
actionbar.setDisplayUseLogoEnabled(true);
actionbar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionbar.addTab(actionbar.newTab().setText(R.string.home_tab_text).setTabListener(this),true);
actionbar.addTab(actionbar.newTab().setText(R.string.insert_tab_text).setTabListener(this));
Fragment fragment = new insert_button_frag();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.button_fragment, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
Here is the layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:id="#+id/button_fragment_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<fragment
android:name="com.bv.silveredittab.home_button_frag"
android:id="#+id/button_fragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<fragment
android:name="com.bv.silveredittab.quick_insert_frag"
android:id="#+id/quick_insert_frag"
android:layout_width="350dip"
android:layout_height="fill_parent" />
<fragment
android:name="com.bv.silveredittab.editor_frag"
android:id="#+id/editor_frag"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
</LinearLayout>
And here is the fragment code
public class insert_button_frag extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
return inflater.inflate(R.layout.insert_buttons,container, false);
}
}
Like I have said. I have tried referencing the fragments parent view to replace it, and the fragment itself (by id) and still, it only adds the new fragment, inside the containing view the original fragment is in.
I solved this by using a placeholder in my Layout and then attaching my Fragment to it at runtime.
Like you, if I instantiated my Fragment within my xml layout then the contents would remain visible after replacing it with another Fragment at runtime.
The problem is this line:
transaction.replace(R.id.button_fragment, fragment);
replace has two overloaded forms. In both of them, the first argument is the container of the Fragment to be replaced, not the Fragment itself. So, in your case, you need to call
transaction.replace(R.id.button_fragment_container, fragment);
edit: I see in your question that you have tried both. I have tested and verified the behavior. This appears to be a bug in the FragmentTransaction API.
Edit2: not a bug after all. You simply cannot replace fragments added statically in a layout file. You can only replace those you have added programmatically ( Android: can't replace one fragment with another )
I had the same issue. Take a look at this link: Android Fragment Duplication
I wonder if the fact that you're passing the container into the inflater.inflate() method causes it to create the new fragment inside of the old one instead of a wholesale replace. I've been providing 'null' to my inflaters in the working version.
Here's the essentials from the version I have working...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View newFrag = new View(getActivity().getApplicationContext());
newFrag = inflater.inflate(R.id.frag, null);
return newFrag;
}
The google developer guide is quite confusing because it shows first to implement hard coded fragment in you xml. But if you really want to replace existing fragment with the new one, then you should add it(the first) at runtime.
What official site state is
FragmentTransaction replace (int containerViewId, Fragment fragment, String tag)
Replace an existing fragment that was added to a container. This is
essentially the same as calling remove(Fragment) for all currently
added fragments that were added with the same containerViewId and then
add(int, Fragment, String) with the same arguments given here.
You should noticed that it says that Replace an existing fragment that was added to container
So, your xml should look like
someActivity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
tools:context="someActivity">
<ImageView
.../>
<LinearLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="bottom"/>
</RelativeLayout>
And than in your activity do in OnCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[...]
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, new FirstFragment).commit();
}
Than you may easily replace fragment with your animations and event add it to back stack in order to save its state.
private SecondFrag getSecondFrag(){
if(secondFrag == null)
secondFrag = new SecondFrag()
return secondFrag;
}
private void openRechargeFragment(){
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.show_frag, R.anim.hide_frag,
R.anim.show_frag, R.anim.hide_frag);
ft.replace(R.id.fragment_container, getSecondFrag(), "myTAG");
ft.addToBackStack(null);
ft.commit();
}

Categories

Resources