How exactly v4.app.Fragment works? I have viewPager with 7 Fragments. I was sure that when moving between fragments, depending on the situation each fragment can be automatically destroyed and created. However it seems not to be true.
I decided to play a bit with debugging and set some flag for my Fragment class object, something like
class MyClass extends Fragment {
public boolean myFlag=false;
When I set ex. true somewhere in the code which is run only once (ex. true is set after button click), it seems that this value is true until the app ends. Thus it suggest the object is kept all the time in memory.
However when user moves between Fragments onCreateView and onViewStateRestored methods seems to be called.
And now I feel quite confused. If Fragments are not destroyed, why those methods are executed by Android?
Do I have the guarantee that my Fragment object will be kept always with all fields (when user only moves beteween Fragments and doesn't leave the app)?
If not how should I save and restore its state? public void onSaveInstanceState(Bundle savedInstanceState) method seems to be only run when user left the app, not when user moves between Fragments.
Have you seen any good tutorial concerning ViewPager and Fragments?
And now I feel quite confused. If Fragments are not destroyed, why
those methods are executed by Android?
If you look at this diagram, Fragments do not need to be destroyed to call onCreateView().
Do I have the guarantee that my Fragment object will be kept always
with all fields (when user only moves beteween Fragments and doesn't
leave the app)?
This depends on what you are doing. If your case is dealing with ViewPager it really boils down to what PagerAdapter you use and your ViewPager configuration.
If not how should I save and restore its state? public void
onSaveInstanceState(Bundle savedInstanceState) method seems to be only
run when user left the app, not when user moves between Fragments.
It depends under what conditions you are wanting to restore state. For example, for orientation changes you can call setRetainInstance(true) on the Fragment and the Fragment's state will be preserved when there is a configuration change given your Fragment is not on the backstack.
Have you seen any good tutorial concerning ViewPager and Fragments?
The Android Guide has a good tutorial.
You can re-initialize all the values of a specific fragment in it's onCreate(...) method. So that when ever it is navigated to, it will have the default values that you setup in your onCreate(...) method.
Here are some useful links related to the Implementation of Fragments in a ViewPager:
1. http://thepseudocoder.wordpress.com/2011/10/13/android-tabs-viewpager-swipe-able-tabs-ftw/
2. http://androidtrainningcenter.blogspot.co.il/2012/10/viewpager-example-in-android.html
3. http://manishkpr.webheavens.com/android-viewpager-example/
4. http://thepseudocoder.wordpress.com/2011/10/05/android-page-swiping-using-viewpager/
I hope this helps.
Related
I have an Activity which can open 2 different Fragments by 2 different Buttons. By the default that Activity when it creates, it is opening a Fragment, we call it "The Main Fragment".
The first Fragment to which we are going over by the first Button we meet zero problems with the Rotation, but the second one after the rotation disappears and the screen shows the Main Fragment's content. When I tried to rotate the screen back, I see the Main Fragment's content again. But why it is so, if I didn't write any code, which must return me to the Main Fragment without clicking a button.
What assumptions do you have?
Why this is happening ?
Default Behavior, Actiivty is getting recreated on orientation change so your fragment are.
Explanation
You need to understand Activity Life Cycle to understand why this is happening.
First, “rotating the screen” is not the actual scenario we are talking about today. Because any configuration change will cause Android to restart your Activity. A configuration change might be the device rotating (because now we have a different screen layout to draw upon), or it could be a language switch (because we need to re-write all those strings, which may need more room now OR it could be the scary RTL switch!), or even keyboard availability.
By reloading your app, what the system is actually doing is calling onDestroy() and then immediately calling onCreate(). This way, your Activity is as fresh as possible, with all of the right creation data (even though the user has been with you the entire time).
Now you have following option -
Either Fix Orientation for your app from AndroidManifest.xml
But oviously that is not a very good experience for user.
Save activityState with onSaveInstanceState()
This method will be called before onDestroy(). And, when your Activity is created, there’s a matching step onRestoreInstanceState(), which will also be called automatically. All of these automatic steps mean that you can let the system worry about saving and loading your data, because you planned ahead and mapped out what was important. (Or, you can skip onRestoreInstanceState() and load your saved state from the Bundle that comes with onCreate().
In you integrate Fragment in activity, because activity is getting destroy() so your fragment will also destroy() and will be recreated.
Please take a good read on Handling Configuration Change and this.
Once you understood the concepts things will start falling into your but it will only happen if you will complete your learning curve.
Happy Coding !
That is because onCreate is being called every time the screen is rotated. Probably you are displaying The Main Fragment from your onCreate method. You will face the same issue if you put your fragment display logic in onResume because just after onCreate, onResume is called.
Solution: store the fragment on top in shared preferences that way you know what to display every time onCreate is being called.
I just started with my first Android project. My application contains two fragments that are connected with the navigation controller.
As for now, all I have on my first fragment is only two EditText. However, I realize that when I switch to my other fragment and navigate back, the texts entered have been cleared.
So I would like to know what I can do to save the date and restore them when I switch it back
I have already tried saving them in onSaveInstanceState() as suggested by the majority of people, however, it is not working. So I did a little test, turns out the onSaveInstanceState() is not even being called when I switch the fragment. Instead, onDestroy() and onPause() are being called, ones where people don't recommend to save my data
I have also tried to use ViewModel to save the data but it seems that the data saved into the ViewModel is also gone when I switch back to the original Fragment.
So I am not sure what to do? Thanks!
You should use ViewModel, create your ViewModel by Activity instead of Fragment, inside your Fragment.onViewCreated() method
val myViewModel = ViewModelProvider(activity as ViewModelStoreOwner).get(MyViewModel::class.java)
I have viewPager with adapter where I instantiate fragment and return it in getItem() method. So when Im on the first page I have only 2 fragments alive. When I rotate the phone, they both get destroyed and garbage collected (system calls their onDestroy() and onDetach() and I can see them in .hprof memory dump as ready to be garbage collected). However, when a new activity is created with new viewpager and 2 new fragments, for some reason, system creates 2 more fragments for those that were destroyed previously and attaches them to the activity, while not adding them to viewPager at all. They just sit in fragmentManager's mActive and mAdded arrays. When I rotate device few times, it creates these new instances each time. Now, this may seem like a leak that causes fragments not to be garbage collected but they indeed are. All these fragments have different #xxx number and are atached to a new activity within a new fragment manager. I've tried everything, any help or suggestions are much appreciated, thanks!
ViewPager handles the lifecycle of the Fragments it shows. As you mention it creates the visible Fragment and the ones next to it (if used with a FragmentStatePagerAdapter) to be able to smoothly swipe into them when the time comes. When the fragment is out of sight, it can be destoryed and recreated by the ViewPager at its will.
The default beheavior for a rotating screen is that the activity is recreated together with the ViewPager and the Fragments.
However this can be changed.
With android:configChanges="orientation" in the manifest you can prevent the activity of being recreated upon orientation change.
The other way of preserving the fragment instance upon an orientation change is to call setRetainInstance(true) in the fragment to be retained.
So I it was (unexpectedly:D) bad code. I had in my Activity's onRestoreInstanceState() piece of code that was creating and setting new adapter and so it put old fragments in background. Sorry for bothering with unanswerable question.
I'm converting all my Activities to Fragments so that I can use them in a ViewPager.
I've searched for this but I couldn't find a satisfying answer, so that's why I'm asking it here.
In my Activities, I've written some code in the onCreate() method. I for example call some findViewById()s in order to link some xml-buttons to my Activity. I also make some views invisible in the onCreate(), set an OnClickListener(), fill a TextView with text and remove a Notification, all in the onCreate() method.
My question is: Where should I put this code in the fragment? In the onCreate()? onCreateView()? onActivityCreated()? and why?
Many thanks in advance!
Although Pragnani's answer is close, there's little educational value in it. Besides, there's a more appropriate option to his 2nd statement.
Where should I put this code in the fragment? In the onCreate()?
onCreateView()? onActivityCreated()? and why?
The short answer is: either onCreateView() or onActivityCreated() will do. The view hierarchy won't be created until onCreateView(), so that's the earliest point in the fragment's life cycle that you could inflate the views and attach click listeners etc. Since onActivityCreated() will always be run after onCreateView(), that's a suitable location too. onCreate() may be skipped in favour of the system temporarily detaching the fragment and reattaching it, e.g. when retaining fragments.
Pragnani is correct by pointing out that inflating the views of a fragment is slightly different from inflating views in an activity. More specifically: a fragment does not define a findViewById() method, so you'll need to call it on some other object.
Rather than using getActivity().findViewById(), you'll want getView().findViewById(). The reason for this is that if you use the activity for the view lookups, then you'll get into trouble when multiple fragments with the same view IDs are attached to it. This will be the case if you reuse view ids in the layouts of your various fragments, or if you show two identical fragments that display different data. In both cases, only the first match would ever be returned, whereas you really want to the view to be looked up in the conext of the fragment. That's exactly what getView() returns, the fragment's root view (that you returned in onCreateView()), and thus limits the scope of the lookup appropriately.
1.Left the onCreate empty and just call super.onCreate()
2.Instead of findViewById() use getActivity().findViewById()
always use getActivity() where you need context of the view.
Do all other operations in onCreateview()
I'm looking at some demo code that shows how to use a Fragment Adapter (Tab Adapter in this case). I'm curious as to what exactly the instantiate() method does. I see it used in the following demo code on this page:
http://developer.android.com/reference/android/support/v4/view/ViewPager.html
(see the getItem() method within the TabsAdapter class)
If I'm reading the demo code correctly, every time a user clicks on one of the tabs, a new Fragment is created? And thus the fragment starts the entire life-cycle again (onAttach()...onCreate()... etc)? This sounds awfully inefficient. I would think that the fragment that will represent the content for each tab should be instantiated only once (perhaps in the addTab() method), and then saved into some collection where it can be fetched when getItem() is called.
Please correct me if I'm mistaken in any of this. I'm trying to better understand how to manage fragments.
My money would be on that the setCurrentItem() function doesn't actually destroy the existing Fragment being shown in that tab. Otherwise there's really not much of a reason for the adapter to have a List of available tabs. Likely, when you switch from one tab to another, setCurrentItem() just detaches the UI from the currently active Fragment (or calls its onPause() method) and then re-attaches the UI for the newly selected Fragment (or calls its onResume() method).
But, if you're in doubt, you could read the source :)
Hope it helps,
David
I was able to find an explanation for my question here