What's the difference between detaching a Fragment and removing it? - android

In the Android docs for a FragmentTransaction I noticed two very similar methods: detach and remove. The descriptions over there don't seem to provide much insight about when to use each, and from what I can tell they appear to be the same.
So: what are the differences between these two methods?

The detach method removes the fragment from the UI, but its state is maintained by the Fragment Manager. This means you can reuse this fragment by calling the attach method, with a modified ViewHierarchy
Remove means the fragment instance cannot be re-attached. You will have to add it again to the fragment transaction.
Source Comment
You'll notice that when a Fragment is detached, its onPause, onStop and onDestroyView methods are called only (in that order). On the other hand, when a Fragment is removed, its onPause, onStop, onDestroyView, onDestroy and onDetach methods are called (in that order). Similarly, when attaching, the Fragment's onCreateView, onStart and onResume methods are called only; and when adding, the Fragment's onAttach, onCreate, onCreateView, onStart and onResume methods are called (in that order). – Adil Hussain

The naming of the fragment management methods are very confusing even according to Google engineers on message boards (see comments above). I made myself a little demo to figure out how things actually work. Here are my findings. Feel free to correct me if I am wrong.
To initially add a Fragment to an Activity, you use:
getFragmentManager().beginTransaction().add(R.id.container, mFragment).commit().
This associates the Activity with the Fragment and also associates a View with the Fragment.
Here are the resulting life cycle events and other important method return values:
onAttach()
onCreate()
onCreateView()
onViewCreated()
onActivityCreated()
onViewStateRestored()
onStart()
onResume()
mFragment.getView() == null: false
mFragment.getActivity() == null: false
To remove a Fragment from an Activity, you use:
getFragmentManager().beginTransaction().remove(mFragment).commit().
This removes any association with a View or to an Activity.
Here are the resulting life cycle events and other important method return values:
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
mFragment.getView() == null: true
mFragment.getActivity() == null: true
I re-added the fragment here
To detach an added Fragment from an Activity, you use:
getFragmentManager().beginTransaction().detach(mFragment).commit().
This removes any association with a View, but keeps the association with the Activity.
Here are the resulting life cycle events and other important method return values:
onPause()
onStop()
onDestroyView()
mFragment.getView() == null: true
mFragment.getActivity() == null: false
To re-attach a Fragment that was detached to the Activity, you use:
getFragmentManager().beginTransaction().attach(mFragment).commit().
This creates a new View to associate with the Fragment and maintains the Activity association.
Here are the resulting life cycle events and other important method return values:
onCreateView()
onViewCreated()
onActivityCreated()
onViewStateRestored()
onStart()
onResume()
mFragment.getView() == null: false
mFragment.getActivity() == null: false
Other important things to note:
If you detach a Fragment and then try to add it again using add() rather than attach(), nothing seems to change.
if you attempt to add a Fragment that has been removed using remove() by using attach() rather than add(), nothing seems to change.
When getView() returns null, the Fragment may still have internal references to the last View it created. This View is no longer valid and should not be used.

Related

Is there any misunderstanding about the onActivityCreated fragment callback?

onActivityCreated seems to mean "This fragment callback is executed just after the activity has been... created... I mean, just after the fragment is correctly attached to the activity. There, you can safely call getActivity, it won't return null, except if the activity is null for some special reason".
However, I've seen that the fragment callback onAttach is called even after OnCreate, it means that the fragment has been attached to the activity, which has been created.
The complete workflow for a fragment (and for a fragment dialog, which is frequently left behind) is: onAttach -> onCreate -> onCreateView -> onActivityCreated. So in each of these 4 methods (perhaps not onAttach I don't know), the activity is normally not null and attached to the fragment.
So my question is: why does the callback onActivityCreated since the activity is, in fact, already created and attached to the fragment 3 callbacks ago???
So basically in onAttach() we get confirmation is that activity is attached to my fragment, I can use getActivity() to fetch things like resources like
getActivity().getResources.getDrawable(R.drawable.abc)
but Suppose if You want to fetch the views inflated in activity's xml like If you want to access
getActivity().findViewById(R.id.Myelement)
You might get null here, so OnActivtyCreated() ensures that activity's view is inflated, You can access activity's views now (Activity's view has been created (onActivityCreated))

Lifecycle of ViewPager

What fragment lifecycle methods (onCreate, onViewCreate, onStart) are called after you setup ViewPager with, say, 10 fragments and call setCurrentItem(9)?
Will there be any difference if you call setCurrentItem(i, false)?
What fragment lifecycle methods (onCreate, onViewCreate, onStart) are called after you setup ViewPager
Every lifecycle method you mentioned plus onAttach, onResume, and onActivityStarted are called. There is nothing about a ViewPager that affects that. Refer to this picture to see the Fragment lifecycle.
Will there be any difference if you call setCurrentItem(i, false)?
No, false does not affect the lifecycle. the only thing that false will do is transition immediately to the page instead of smoothly across the ViewPager.
The onPause, onStop, etc. methods may be called after you scroll out of view of a Fragment, but that was not part of your question. ..

what is the different between onCreate() and onCreateView() lifecycle methods in Fragment?

I don't know when to use onCreate() or onCreateView().
I have used onCreate() and onCreateView() lifecycle methods.
I think onCreate() for Activity and onCreateView() for Fragment. But I am not sure. Can I use onCreate() LifeCycle method in Fragment? I hope somebody can help me!
onCreate is called on initial creation of the fragment. You do your non graphical initializations here. It finishes even before the layout is inflated and the fragment is visible.
onCreateView is called to inflate the layout of the fragment i.e graphical initialization usually takes place here. It is always called some time after the onCreate method.
Activity lifecycle explained - http://developer.android.com/reference/android/app/Activity.html
Fragment lifecycle explained - http://developer.android.com/guide/components/fragments.html#Creating
Detailed lifecycle diagram - https://github.com/xxv/android-lifecycle
From documents :
onCreate
Called when the activity is starting.
This is where most initialization should go: calling setContentView(int) to inflate the activity's UI, using findViewById(int) to programmatically interact with widgets in the UI, calling managedQuery(android.net.Uri, String[], String, String[], String) to retrieve cursors for data being displayed, etc.
You can call finish() from within this function, in which case onDestroy() will be immediately called without any of the rest of the activity lifecycle (onStart(), onResume(), onPause(), etc) executing.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
Link to documentation of onCreate
onCreateView
Called to have the fragment instantiate its user interface view. This is optional, and non-graphical fragments can return null (which is the default implementation). This will be called between onCreate(Bundle) and onActivityCreated(Bundle).
If you return a View from here, you will later be called in onDestroyView() when the view is being released.
Link to documentation of onCreateView

handling Fragments on Config Change

My application contains two fragments.
My Android manifest file contains the following line:
"android:configChanges="orientation|screenSize"
which I need for the second fragment. I don't want its onCreateView() or other method to be called an orientation change.
But my first fragment needs onCreateView() to be called when orientation changes. Since the manifest file contains the above line, the onCreateView() method is not called. Can anyone help me in sorting out this to make onCreateView() to be called when orientation changes for specific fragment?
I believe setRetainInstance() is the function you need.
From documentation:
Control whether a fragment instance is retained across Activity
re-creation (such as from a configuration change). This can only be
used with fragments not in the back stack. If set, the fragment
lifecycle will be slightly different when an activity is recreated:
onDestroy() will not be called (but onDetach() still will be, because
the fragment is being detached from its current activity).
onCreate(Bundle) will not be called since the fragment is not being
re-created.
onAttach(Activity) and onActivityCreated(Bundle) will
still be called.

onAttach activity is null

In creation of a fragment, I encountered getActivity() to be null.
So to narrow down the problem, I kept a local copy of activity in onAttach(Activity activity), which by definition is when it is attached to an activity.
However, I logged the activity in onAttach, and it is still null.
I'm only running into this problem in 2.3.6 and below.
Is this a known problem with support package?
The series of methods called to bring a fragment up to resumed state are:
onAttach(Activity) called once the fragment is associated with its activity.
onCreate(Bundle) called to do initial creation of the fragment.
onCreateView(LayoutInflater, ViewGroup, Bundle) creates and returns the view hierarchy associated with the fragment.
onActivityCreated(Bundle) tells the fragment that its activity has completed its own Activity.onCreate().
onViewStateRestored(Bundle) tells the fragment that all of the saved state of its view hierarchy has been restored.
onStart() makes the fragment visible to the user (based on its containing activity being started).
onResume() makes the fragment interacting with the user (based on its containing activity being resumed).
The bold method should be the one where getActivity doesn't return null anymore.
the onAttach method should not be used to call methods of the activity object, It should be used to initialise callback interfaces. An example of these interfaces can be found here.
This problem is because of the support package it means the fragment are from android 3.0 and up that is API level 11 and UP so for sure you will face app crash for android 2.3.6 gingerbird
this.getActivity();

Categories

Resources