I have a tabbed application, say 2 tabs. It was initially developed using ActivityGroup. However, having realized that multi-panes are not supported in ActivityGroup, I decided to use fragments. Before going to the problem, let me brief you about the application.
So, like I said before it is a tabbed application
TabA---> Activity1---> Activity2---> Activity3
TabB---> Activity4---> Activity5----> Activity6
This is the work pattern of my old activity-group based app.
Now with fragments, this would change into something like below
FragmentActivity---> TabAFragment---> FragmentA1---> FragmentA2
|
---> TabBFragment---> FragmentB1---> FragmentB2
Each fragment connects to server for data on initial load.
And in the transaction, I replace fragment every time I add.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.realtabcontent, fragment);
ft.commit();
What is observed
I have only one activity(FragmentActivity-where tabs are created) for those two tab fragments. I share this activity for all tabs. For instance, I load fragmentB1 in tabB- inflates a view, fetches data from server and displays in a ListView. Then I switch to other tabA and loads fragmentA1. So far so good. Now if I go back to tabB, I want to see the listView which was loaded earlier. What happens is it starts everything from square one.
This is my first-hand experience with fragments. I did a bit of research; however it didn't really help fix mine.
How can I retain already loaded view?
Any thoughts?
Hi I'm fairly new to all the fragments also. However, I was doing something similar and found that I needed to add the current fragment to the back stack like so.
ft.addToBackStack (null);
This line would go just before your comit so your code becomes:
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.realtabcontent, fragment);
ft.addToBackStack (null);
ft.commit();
Hopefully this is of some use.
Related
EDIT: I want to solve problem of duplicating fragment in view Pager, removing them isn't the best solution.
I have a problem with FragmentManager in my app. Every time when I click "Wykłady teoretyczne" or "Wykłady popularnonaukowe" on Navigation Drawer my app is creating new fragment ScheduleFragment() which contains ViewPager and in SchedulePagerAdapter app is creating new 3 fragments (ScheduleEventFragment()) to swipe them in ScheduleFragment. My problem is that FragmentManager doesn't remove old ScheduleEventFragments, for all the time it keeps them in memory. How can I fix this problem?
I have my project on GitHub, please check it.
There you have screen from debuging
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.remove(R.id.container,fragment,optionalTag);
fragmentTransaction.commit();You can also detach or replace
Always check if fragmemt.isAdded() and then only add the fragment if not.
I working on a app whitch has 1 activity with 2 buttons (Map and Listview). By clicking on the buttons the fragment into the FrameLayout needs to change from a listview to a mapview (or from map to listview).
I got this working and the fragments are show the data exacly as i want BUT...
I have a few problems by switching between the fragments. I struggled with the code and the best i got working is this:
FragmentManager fragmentManager;
Fragment listOverview;
AlertOverviewMapsFragment mapsOverview;
#Bind(R.id.fr_overviewContainer) FrameLayout fr_overviewContainer;
#OnClick(R.id.btn_list_overview) void openListOverview()
{
// Add the fragment to the 'fragment_container' FrameLayout
if (listOverview == null) { listOverview = new AlertOverviewListFragment();}
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fr_overviewContainer.removeAllViews();
fragmentTransaction.add(R.id.fr_overviewContainer, listOverview).commit();
}
#OnClick(R.id.btn_maps_overview) void openMapsOverview()
{
// Add the fragment to the 'fragment_container' FrameLayout
if (mapsOverview == null){ mapsOverview = new AlertOverviewMapsFragment();}
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fr_overviewContainer.removeAllViews();
fragmentTransaction.add(R.id.fr_overviewContainer, mapsOverview).commit();
}
The problem is when i click a second time on a button the app crashes and i get a java.lang.IllegalStateException: Fragment already added error. I understand that it means that i added the fragment to the manager (or transaction, dunno). I can create or find some workarounds for this but since this is nothing new i'am looking for the usual way to switch (replace) between the 2 fragments.
The fragments contains data which are loaded from the internet, it will be nice when the data is saved and loaded again by reloading the fragment. (so the user sees the old data when it is updated again in the background)
A CLEAR code example would be nice.....
i read something about the fragment manager and transactions and so as i understand the manager makes it posible to add, remove, delete......... fragments from a transaction? so i need 1 transaction per activity? or is this twisted? so the manager contains the fragments? this part is not clear and realy complicated for me. I'am happy when someone can help me with a solution for my problem and it would be nice when someone can explain how the transactions and the managers work in a realy SIMPLE way becouse i'am just started with programming Android apps.
Thanks for reading my problem and lot more thanks for the people who takes the time and patience for writing an answer!
Fragments is something that I am still trying to understand, I get some of it but not all of it.
My question is, do i need a container to start a new fragment instance?
This is what I have been currently doing to launch a fragment from my current activity that i have a container in.
FragmentManager fm = getActivity().getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(container.getId(), new OtherFragment());
ft.commit();
So my main activity has a container where I can switch from 4 fragments. Now lets say I click on one of the list items in my 3rd tab. That launches a new activity that shows another listview. Then if i click on the item on that listview, i launch a new activity. Then, were it says "tap for more information", I will be launching a new activity (I haven't created this yet, and that is why I am asking this).
But I feel like it could just be launching fragments instead of activities. If so, how do I go about doing that, because I feel like I need some type of container to put it in since I have tried launching a newinstance of a dummy fragment class i created it but it doesn't launch. If not, how do i just create a new instance of it without a container, if possible.
Or do I only use fragments whenever they will be similar and will have a container to be put in??
And I could do fragmentActivity, but that is almost the same as Activity. The reason I ask is because we shouldn't have so many activities, right? or does having as many as activities as you want not affect the project performance? Because right now I usually create activities for everything, unless its like the first picture where I will have something similar that can be put into a container.
Thanks.
You're going to to pretty much the same thing that you did to show the first fragment.
FragmentManager fm = getActivity().getFragmentManager();
if (mDetailFragment == null)
{
mDetailFragment = new DetailFragment();
}
FragmentTransaction ft = fm.beginTransaction();
ft.replace(container.getId(), mDetailFragment);
ft.commit();
You're going to want to keep references to your fragments so you're not creating them new every time. To improve the user experience you can add animations to the transition and, if it makes sense, add the fragment to the backstack.
ft.addToBackstack("OtherFragment");
ft.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.popEnter, R.anim.popExit);
There're two parts to this question.
Suppose we have an Activity and then two fragments: a ListFragment and a Fragment (which will be shown when you click an item from the ListFragment).
Part 1
Where should I close the fragment? By this I mean what would be considered good from a design point of view. I see two options: one declaring an interface in the fragment and having the activity implementing it, let's call it closeFragment(). This would be a way to communicate from the fragment to the activity like shown in the Dev Site. The other one is probably quite simple and is calling getActivity().getSupportFragmentManager() and using the manager to close it.
Part 2
I know how to create a fragment and replace it since it's on the Dev site but I have doubts about closing one. How should I actually close it? Is something like the following code correct? Suppose that the fragment was added to the BackStack.
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
getSupportFragmentManager().popBackStack();
transaction.remove(this);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
transaction.commit();
Thank you very much.
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.remove(this);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
ft.commit();
I would prefer having a dumb fragment , which don't know anything about where it is being used , so that you could use it on any activity you wish , and it would have the precise goal you've set for it . Of course , you can do whatever you wish .
This looks like closing it , but I would prefer replacing it instead . You can also always return to the fragment as long as you have a reference to it .
I am using Fragments to represents different views in my application. I replace the fragments using the following code when navigating between views:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.main_linearlayout_fragmentcont, frag);
ft.addToBackStack(null);
ft.commit();
I have run into a number of problems when rotating and the activity is reconstructed. I need to support old versions of android so android:configChanges="orientation" isn't an option. A lot of the issues are due to the nature of how Android saves Fragment state.
These are the problems I am running into:
1) The Fragment transitions don't remember my custom animations for pop events when they are restored automatically after a rotate. They do however remember my BackStack. I know I can write my own back handler that does a replace using animations and get rid of pop all together but I was wondering if there is a way to either reset the animation before calling popBackStack() or a way to have the FragmentManager remember the animations when it auto restores after rotate.
2) The other issue I have is that I have a bunch of child views (linearlayouts) in one of my top level fragment views that contain their own fragments. These child views are created and populated programmatically. When my fragment is recreated after rotation, I programmatically reconstruct the child views in onCreateView of the Fragment Object and I end up with duplicate fragments under each of the child views (1 - I create programmatically and 1 - Android Fragments create from restore). I am assuming this is because I programmatically reconstruct the child views after rotation with the same id. Is there a way to prevent Fragments from being restored? When does Android inject the Fragments from savedState into these views I construct programmatically? How would I prevent this from happening?
3) The above replace code seems to fire onCreateView multiple times for my frag (Fragment) object. This is without rotation and happens when I run the above code only once. Is there a reason that onCreateView of a Fragment would be called multiple times with the above code?
Questions about Fragments:
1) Can I prevent Android from auto restoring fragments when an activity is reconstructed? How would I go about this? Is it based on the ID of the LinearLayout? Could I call removeAllViews of the LinearLayout containing the fragment onStop? That way the view doesn't exist when it saves?
2) Is there a way to add a Fragment to a LinearLayout that I have a reference to but that doesn't have an ID? It appears the Fragment add, replace APIs require an int ID.
Thanks!
1) if you find out how let me know, I'm also pissed off by that
2) you're probably calling add on the FragmentTransaction inside the top level fragment, but the restore operation is also adding, so duplicates! option 1. Use replace instead. option 2. (preferred) Check if(savedInstances==null) { // do transaction } else { //let the system rebuilt it itself}
3) If you're changing the layout (by calling add or replace) of a view that is a part of a fragment, the manager call the method to creates the view again. I'm still not sure if that is a bug or a feature, and if it's a feature why it is. If you find out let me know
1) (supposed to be 4, no?) don't mess with the layouts, if u want to remove, remove them using while(popBackStackImmediatly){}, but if you go deeper and understand what the system is doing, usually there's no reason to not let it do it automatically.
2) (supposed to be 5, no?) if you have a reference you have the id View.getId()
happy coding!
If you are change the orientation of device then check the validation in activity and it also manage the fragment with stack so your flow not damage in that case.
if(savedInstanceState == null) {
mFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
mFragmentManager.beginTransaction();
FragmentOne fragment = new FragmentOne();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
}