Access a detached fragment's view - android

I currently am using ActionBar's tab feature with multiple fragments each representing a tab.
On my last fragment there is a 'Submit' button that takes all the input that the user has done on all the fragments and submits it.
My problem is that since those other fragments have been detached (only the currently showing fragment is attached to the main view) their view gets destroyed so cannot be accessed using the fragment's findViewById().
How can I access the data the user inputted for these fragments? Interestingly, it does store all the inputted values in a bundle and restores them when the fragment is attached again, I'm thinking the answer lies somewhere there...

I fixed this by not calling .detach() but .hide().
Now in the activity findViewById() will actually be able to access the view of all its fragments since their UI is now not detached just not showing.

Related

Restore fragment's previous state on rotation and position in backstack

I have an app with a single activity showing a fragment to the user. On a click on a button, the activity shows another fragment but keeping the previous one in the backstack. I have now two problems:
On rotation (particularly in the second fragment), the data entered in the EditTexts is cleared
I want the backstack to be also restored with the text previously entered in the second fragment.
The problem is that when I save data to bundle using OnSaveInstanceState(...), I successfully get it again from OnViewCreated(...) but when I use editText.setText(str), the text is not shown.
At the moment, I think this is because the fragment is then destroyed and recreated by the parent Activity.
How can I do to make it work properly?
Thanks.
Make your fragments retainable:
setRetainInstance(true);
See the following guideline on orientation change state android orientation changes `

Re-inflate different layout View in same Fragment in onResume

I have a Fragment, MainFragment, which can contain two, three, or four nested fragments. The specific fragments that will be shown can be changed by the user in the settings.
There is a different layout for each number of fragments. For instance, layout_3 is used when the user chooses three nested fragments.
What I need to do is dynamically update MainFragment's layout, and which fragments will be nested within that layout, in onResume() (i.e. Once the user comes back from the settings). There are about 10 fragments the user can choose from, and I need to be able to swap them in and out of MainFragment dynamically.
I'm having trouble doing this. The only way to update the layout/view once I return from the settings is to leave MainFragment and then come back (which calls onCreateView()).
Here is an example of what I do in onCreateView() to initialize the layouts (two nested fragments is the default):
mView = mInflater.inflate(R.layout.layout_2, mParent, false);
getChildFragmentManager().beginTransaction().add(R.id.fragmentContainer1, fragment1).commit();
getChildFragmentManager().beginTransaction().add(R.id.fragmentContainer2, fragment2).commit();
return view;
Suppose the user then goes to the settings and chooses to have three nested fragments. This is what I've tried in onResume(), to no effect:
mView = mInflater.inflate(R.layout.layout_3, mParent, false);
getChildFragmentManager().beginTransaction().add(R.id.fragmentContainer1, fragment1)).commit();
getChildFragmentManager().beginTransaction().add(R.id.fragmentContainer2, fragment2).commit();
getChildFragmentManager().beginTransaction().add(R.id.fragmentContainer3, fragment3).commit();
I'm not sure if I'm doing something wrong. Ideally, I would just force MainFragment to call onCreateView() again, but none of the solutions for that problem seem to work.
Any ideas? Thanks for the help.
Edit: I believe the problem is with inflating the new View, rather than replacing the fragments.
For instance, suppose the default screen is layout_4, with four fragment containers. The user then goes to the settings un-checks all four default fragments, and chooses three new fragments. In onResume(), we try to inflate layout_3, and then add the fragments. I think layout_3 never inflates, but because my fragment containers have the same style id across layouts (i.e. fragmentContainer1 - fragmentContainer4), the first three fragment containers are updated. The fourth one remains as it was, since I assumed we were in layout_3 and did not try to update it.
This behavior is confirmed and results in a crash when the user tries to increase the number of fragments, rather than decrease. Above, when the user switched from four fragments to three fragments, there was no crash because all three fragment containers I tried to update exist in layout_4. But if the user is in layout_2 and then goes to the settings to select a third fragment, we'll try to add a fragment to fragmentContainer3 when we resume. This results in a crash because layout_3 fails to inflate.
java.lang.RuntimeException: Unable to resume activity
java.lang.IllegalArgumentException: No view found for id 0x7f0c005f
Any ideas how to fix this? The call to re-inflate mView in onResume() does not seem to have any effect.
Edit 2: I've tried calling mParent.addView(mView) after inflating, but still experience the same behavior as above, for the most part.
When you return from the settings, onResume() should be called in the MainFragment and subsequently any nested fragments that were already loaded in the MainFragment. Can you not include any update logic in the nested fragments' onResume() instead of only in onCreateView()?
Otherwise you can create a different code path and put update logic there: make public methods in the classes for fragment1, fragment2, fragment3 that include all your update logic, and call those methods from somewhere in MainFragment. (You could create an interface and have the nested fragment classes inherit that interface, if they are different classes and you want to have a cleaner design.)
Be careful about whether or not the nested fragments have been resumed yet—calling methods on View objects when nested fragments' onResume() hasn't been called yet could be problematic.

Why is my fragment onCreate being called extensively whenever I page through my applications viewPager?

I'm not quite understanding this fragment lifecycle business.
I have a pretty standard 3 page horizontal slider view Pager layout for a "view details" section of my app. I start my app on the middle page of the three. My FragmentActivity sets the page to page 1.
mPager.setCurrentItem(1); //default to center page, current data view fragment
I've been using the FragmentStatePagerAdapter because using the FragmentPagerAdapter crashed my app at times, when coming back from a suspended state for example, and this was the quickest way to work around that for now. Seems to work but I suspect the State aspect is what might be the cause of my problem here, maybe.
So at first I thought that I would have each fragment do the work of getting data from a rest service and then showing it in a list, but I'm not so sure any more.
I tried running a unique async task to fetch data in each of the fragments onCreateView events.
Then after reading more on the fragment lifecycle I switched to onCreate, having noticed that the onCreateView was being called quite heavily, which in turn made for a greedy app that too often requested data over the wire.
Switching to onCreate hasn't changed anything. OnCreate is still geting called just as much as onCreateView for the 2 adjacent fragments.
The odd thing is that the fragment that I set to be the first one to display in Fragment Activity only gets the onCreate called the one time.
Something doesn't feel right here.
Right now I'm thinking that I should have the parent fragment activity declare and call all the async tasks to fetch the data that I need to display in the fragments.
Set the results of the async calls in an object owned by the parent fragment activity and then have the fragments use the object contained by the parent to create the list view etc.
But what if the async tasks started by the parent activity don't finish before each fragments onCreateView is called and the object contained by the parent isn't ready yet.....
signed, confused and frustrated
ViewPager is quite zealous in shutting down things it isn't currently using, and this is exactly what is happening here. The default behaviour is for ViewPager to "keep around" one page either side of the page being viewed, and destroy the rest. Hence in your 3-page view, page 3 gets destroyed when selecting page 1, then when page 2 is reselected page 3 is recreated. As you've noticed, page 2 only has onCreate(..) called once because it is always adjacent to, or is, the currently selected page.
To solve this, simply set ViewPager.setOffscreenPageLimit(2). Then the ViewPager will keep all your Fragments. Obviously this isn't a good idea for a large number of Fragments, but for your case it should be fine.
#Espiandev's solution will work for your current case, but you're right that your state is the issue. You should use the setArgument and/or onSaveInstanceState methods to save your Fragment's state (which shouldn't be too hard, since e.g., a response from the server can usually be represented as a String), and then use getArgument and/or the Bundle passed in onCreate to restore it.
Alternatively, you could have your Activity do the server fetches, and then call setArgument for each of your fragments, and check the arguments inside your Fragment to determine if your data has arrived yet (and if not, potentially display a loading state of some kind).
If you care at all about screen orientation change, this related question will also be useful to you.

Fragment LIfecycle in Custom Tab View

I have a custom widget that performs FragmentTransaction.replace when buttons are pressed. Currently, my code is set up such that the first time a fragment is created, it attaches a bunch of stuff to the view that isn't originally part of the xml layout file.
When the app first launches, all my fragments show stuff correctly, however, let's say I start on Fragment A. I can then transition to Fragment B (with B showing up correctly), however, when I transition back to Fragment A, all the stuff I have attached to the view of Fragment A is now gone. I know this happens because onCreateView is called which probably means the Fragment's view is re-generated when FragmentTransaction.replace is called.
Is there a way where I can keep my fragments around instead of having them re-generate their views when FragmentTransaction.replace is called?
Thanks!
Instead of using fragmentTransaction.replace, use fragmentTransaction.show and fragmentTransaction.hide.
That will keep your fragments from being destroyed.

Android:Saving Fragment State/contents of each views in each Fragment when using ViewPager

I really,really need a serious help over here.
I am creating an android app which uses PagerAdapter to create Fragments in an activity. Different Fragment consists of different views according to need which are created during run time. In the last fragment, I have created a sort of "Submit button", which when clicked, is supposed to get user entered values from each views(like EditText) from all Fragments.
I am using following command to get the views(int the above mentioned button clicklistener):
EditText e = (EditText) (getActivity().findViewById(i));
But its not geting the view with that ID except of last two fragments.
So, I am assuming that, it is saving the state of only last two fragments in that activity.
So, How can I save the 'view states' of all the fragments in the activity??
And Isn't it so that, when a view is created in a Fragment, and is added in its layout , that view is also added in the main activity layout?? Am I understanding it in the wrong way??Please let me know.
To simplify it, my question is:
How can we save the contents, entered by users, in dynamically created EditText in Fragments, created using the ViewPager (So that it can be accessed later)??
When you add a fragment to a FragmentPagerAdapter (assuming you haven't written a custom pager) it is added to the FragmentManager. The Fragment manager is independent of the activity lifecycle so it retains the fragment state.
If you take a look here: http://code.google.com/p/ratebeerforandroid/source/browse/trunk/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentPagerAdapter.java?spec=svn42&r=42
You can get an idea of how it works. If you want to save the fragment state for another session you'll need to pull back each fragment (getItem) and either use the onSaveInstanceState or write your own custom function
Hope that helps

Categories

Resources