I'm all new to Android Development but already in big trouble. I've read several threads both here and on other sites regarding a similar or even the same problem. But all of the answers I've found don't fit my needs or aren't working for me at all.
So here's the thing. I'm having a single Activity with a self-made "menu" layer including 3 buttons at the bottom of the activity and a ScrollView above. Now on clicking one of those buttons I simply inflate a fragment into the ScrollView using
svContent.removeAllViews();
getLayoutInflater().inflate(R.layout.fragment_xyz, (ScrollView) findViewById(R.id.svContent));
which is inflated perfectly fine.
Now the inflated fragment includes another fragment for Google Maps (API 2), which looks like this.
<fragment
android:id="#+id/fMap"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="fill_parent"
android:layout_height="150dp" />
This fragment is also populated just the way I want on its parent fragment's inflation and the map is working fine.
Now I click on another menu button to have another fragment being inflated. But right when I click the button for the first fragment again, I get the following error:
Duplicate id xxxxx, tag null, or parent id xxxxx with another fragment for com.google.android.gms.maps.MapFragment
Like I said, I've tried several solution I found online including
moving from extending Fragment to FragmentActivity
using SupportMapFragment instead of Fragment
inflating the sub-fragment (the Google Maps one) from code instead of XML
All of these had several disadvantages I cannot accept at the moment (at least I think) or "didn't work" for me or in my constellation
Any help is greatly appreciated. And please me know if you need more information.
Regards,
D.
To replace the fragment in your ScrollView :
SupportMapFragment mapFragment = MapFragment.newInstance();
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.svContent, _mapFragment );
ft.commit();
If you want to go back to the previous frgament with the back button, add ft.addToBackStack(null); before the commit.
And that's it.
By the way, you should probably not have a ScrollView as the container of your fragments. If the content must be scrollable, put the scroll in your fragment and put the fragment in a LinearLayout/FrameLayout/RelativeLayout.
To handle fragments, you should use the FragmentManager. This means that you should not inflate a fragment directly. Rather, you should allow the FragmentManager to do it for you.
you need to make map to null when user navigates to another screen.
destroy google map instance when onDestroy method.
#Override
protected void onDestroyView() {
Fragment fragment = getFragmentManager().findFragmentById(R.id.fMap);
getFragmentManager().beginTransaction().remove(fragment);
gMap.clear();
gMap = null;
super.onDestroy();
}
Related
I have nested fragment, fragment inside fragment. Using NavigationBottomView. Everything goes right when I backpress from parent to child fragment.
But now, if I am inside child fragment and suddenly my phone screen goes off, and if I Open the screen again and backpress from where I left, it's not going I think it is forgot or clear my backstack. Don't know why. I have made a demo on github link below
MessageListningFragment messageListningFragment = new MessageListningFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.addToBackStack( null );
transaction.replace( R.id.dynamic_container, messageListningFragment ).commitAllowingStateLoss();
github demo link is here
You should either use a ViewPager/ViewPager2 with NavHost fragments or implement BottomNavigationView with extension functions Google provided, which basically tags fragments and add them with NavHostFragment.create().
NavHostFragment takes care of childFragmentManager and back stack management. You can check out examples here if you wish.
I have an android application that uses one activity and a number of fragments to build a ui dynamically
The base activity has a simple LinearLayout in it that has nothing (BaseActivity)
I add a fragment to it that only contains a drawer layout with an actionbar a framelayout and a navigation bar (BaseFragment)
To that I add one of two fragments, one shows all children as lists (SerialFragment) , the other in a wizard style (WizardFragment)
Each of those can add one (in case of a wizard) or many (in case of a list) fragments (QuestionFragment)
When I navigate away from BaseActivity then the BaseFragment's onDestroy() gets called, but not the onDestroy() of any of the child fragments
I add the child fragments like so
FragmentTransaction trans = parent.getFragmentManager().beginTransaction();
set_default_animation(trans); //this just adds a custom animation
trans.replace(R.id.wizard_content, QuestionFragment.NewInstance(),question_id.toString()); //in case of a wizard
trans.add(R.id.list_content,QuestionFragment.NewInstance(), question_id.toString());//in case of a list
trans.commit();
The only difference between the BaseFragment (which gets destroyed) and the others, is that in the others I add a tag to them (section_id or question_id) so that I can retrieve them using findFragmentByTag.
Yet when the user navigates away from the activity only BaseFragment's onDestroy() is called.
Is the reason for this the fact that , that fragment is the only one I haven't added using a tag?
Note that I am not using a support fragment manager, the normal one, so I use tags to locate the fragments I want , since the non-support fragment manager does not contain getFragments().
Also note that I have not set the retain instance flag to true on any of the above mentioned fragments
I could test the above by removing tags and adding references to the fragments on the parents, but that means a LOT of refactoring which I would like to avoid if that is not the problem.
Thanks in advance for any help you can provide
After refactoring everything, it seems that the tags weren't the problem (though I still removed them)
What fixed it for me, is using getChildFragmentManager() instead of getFragmentManager() to update the gui
That way when the base view gets destroyed its children are removed aswell
Hope it helps someone
I'm working on a simple Android App as a self-learning Project. I've got a lot of it functioning, and I have a main Activity which has a FrameLayout and some RecyclerView and FloatingActionButton stuff going on inside of it.
However, I want to make one of my buttons in my NavigationDrawer open a different view in the FrameLayout using Fragments. Is there a way to do this, sort of making a new Fragment for the RecyclerView and the other stuff and putting the RecyclerView and FloatingActionButton in there?
I tried doing something like this (when the appropriate NavigationDrawer button was clicked):
statsFragment = new StatsFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.rootLayout, statsFragment);
transaction.addToBackStack(null);
transaction.commit();
But this caused my app to crash. Any pointers?
Is your R.id.rootLayout a Layout or a Fragment component?
If your main Activity has a hard coded Fragment (by hard coded i mean declared in your XML), then no, you can't change a hard-coded fragment content with FragmentTransaction.
More information on this question's answer.
Finally, you can't put your components from one Activity inside a new Fragment/Activity since each component belongs to one and only one Context.
See, Activity extends Context. When you get a reference to a component declared in your XML by using Activity.findViewById(int), you are actually making a pointer to a determined View from this Activity's layout, defined in your onCreatemethod with setContentView(id). You can't take this pointer and throw it to another Fragment or Activity within your application without expecting any problems. (Well, maybe you can, but it's totally against the best practices of Android Programming).
I have an activity which hosts 3 fragments in a ViewFlipper. Each of those three fragments hosts fragments of their own. I am using the ViewFlipper like a tab control, which allows me to very simply switch between various "views" in the app. This all works fine, so far.
When the user is inside a view, there is a navigation flow. I use:
final FragmentTransaction txn = getChildFragmentManager()
.beginTransaction();
txn.replace(R.id.view1_silo_container,
new View1Fragment());
txn.addToBackStack(null);
txn.commit();
to move around inside this view. So as the user navigates, I call some variation of the code above to replace the current fragment with a new one. Again, this all works fine so far.
The problem is that, when I get to the bottom fragment (A>B>C) and then I hit the back button to go from (C>B) I get a duplicate id error. The problem is that the "B" fragment itself has a fragment nested in it. As long as I avoid giving this fragment an id, there is no problem. However, if I give this fragment an id then I get "Duplicate id, tag null, or parent id 0x0 with another fragment".
I don't understand why this is a problem, and I haven't found a way to work around it. Am I doing it completely wrong? Is there some small piece I am missing?
The answer is:
Note: You cannot inflate a layout into a fragment when that layout includes a <fragment>. Nested fragments are only supported when added to a fragment dynamically.
This can be found in the Android 4.2 APIs documentation about the new nested fragments feature.
Once I removed the <fragment> from the layout and used getChildFragmentManager() to insert the fragment 'manually' in onCreateView, it worked fine. No more duplicate errors.
I am learning fragments but I am failing to understand the significance behind why fragments requires a Container.
The way I understand Fragments work is as follows :
FragmentActivity setContentview refers to a xml file which
defines where fragments would be located.
FragmentActivity creates instance of the fragments
Then assigns fragment to container.
FragmentManager then displays them.
The actual Fragment class then inflates a layout, and it is this layout which
contains all of the applications UI components.
(please correct me if I miss something here because I am only learning at the moment).
So why is the purpose of the Container why do we even need since in all the examples I have seen it is just a blank relative layout xml document.
Can different fragments share the same Container (since its just a RelativeLayout xml file)?
So in the example provided by google http://developer.android.com/training/basics/fragments/creating.html
They have a ListFragment and when item is selected through the use of the CallBack interface we eventually get back to this line of code :
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
My other question is:
1) Why does this line of code not replace the ListFragment (left side Fragment) with the article fragment. Since when it was initialised we see:
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
Instead ... the ListFragment remains on the left and the right Fragment is updated.
But the container fragment_container belongs to firstFragment this is the ListFragment.
And this is not the one that gets updated.
Do you see why I have the question ? This is not explained in the tutorial.
Here: http://marakana.com/s/post/1250/android_fragments_tutorial
And here: http://developer.android.com/guide/components/fragments.html
Read this and all will be clear:)
Fragment is a portion of Activity and can exist only inside an Activity. So you need a special type of activity that can handle fragment - it's FragmentActivity.
FragmentActivity without Fragments is almost like a normal Activity. But it has a FragmentManager to manage (add,remove,replace) fragments. When you want to add a Fragment to a FragmetnActivity you should specify where it should be placed (because fragment does not need to be fullscreen, just like GooglePlay-there are multiple small fragments). So this is why you need a container.
Can different fragments share the same Container (since its just a RelativeLayout xml file)?
Yes they can, you can replace one fragment with another within the same container.