I need to recreate a fragment when user press a toggle. I'm using this function:
public void refreshFragment(){
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (Build.VERSION.SDK_INT >= 26) {
ft.setReorderingAllowed(false);
}
ft.detach(this).attach(this).commit();
}
It works fine, but when calling it, onCreate isn't called, this is the sequence of methods called after recreate:
onCreateView()
onViewCreated()
onResume()
And this this is the sequence of methods called when creating it for the first time:
onCreate()
onCreateView()
onViewCreated()
onResume()
Appearently, onCreate is never called again when refreshing the fragment with that function. This will be as is for ever? Or in some circumstances can change? I'm asking it because it's perfect for me that onCreate only gets called the first time, because then I can put there code that I want to execute only one item and not when refreshing. But I need to know if it's safe or onCreate can be called when refreshing.
onCreate() will only be called when your fragment is being, well, created. Detaching and reattaching don't create new fragments, but onCreate() will also be called if your activity is destroyed and recreated (e.g., on a configuration change like rotation or if your app's process is killed).
Related
I am trying to redesign some fragments to remove dependencies from the onAttach and onActivityCreated overrides and instead look up the Activity later on in the onViewCreated override.
Are there any cases in the Android application lifecycle where onViewCreated for the fragment is called before Activity onCreate finishes. For example I know that:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
will usually not result in Fragments onAttach being called (assuming the fragment is added to the fragment manager programmatically later on), however in rare cases with configuration updates the fragment manager can recreate the fragments in the super.onCreate which causes the onAttach to be called before onCreate for the activity has finished.
onCreate()
The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.
onCreateView()
Called to create the view hierarchy associated with the fragment.
The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.
Refer Fragments Life Cycle
I am maintaining a backstack of fragments and pop the stack when back button is pressed. I need to reload data every time a fragment is made visible and do some cleanup when it gets hidden. For this I need to detect when a fragment is shown and hidden. This is a very common question but surprisingly none of accepted answers work for me. I
I am adding fragments to backstack using code like this:
public void pushFragment(Fragment f) {
getFragmentManager().beginTransaction()
.add(R.id.content_frame, f, null)
.addToBackStack(null)
.commit();
}
I am popping fragments off using this code:
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
I am trying to detect from a fragment class when it becomes visible or hidden (either because it is being popped off the stack or another fragment was pushed on top). So far I have tried these callbacks:
onViewCreated/onDestroyView: Only called when the fragment is added to stack and popped off the stack. Not called when the fragment gets hidden or visible because of other fragments on the stack.
onHiddenChanged: Never called. Many have said on SO that this works. But not working for me for some reason.
setUserVisibleHint: Never called
onStart/onPause etc: They don't really apply here because they simply reflect the lifecycle of the host activity.
Is there a Fragment callback that will let me detect when a fragment is being shown or hidden? I will rather not use a backstack listener because I want every fragment class to have its own show/hide logic.
Edit:
If I use replace() to add the fragment (instead of add()) then the view for the previously shown fragment gets destroyed. As a result if that fragment ever to appear on top of the stack again its view is recreated. In this situation onViewCreated/onDestroyView or onStart/onStop will be called every time a fragment is shown or hidden. I suppose I could use that approach. The down side is that the views are created and destroyed frequently. I might as well be using activities instead of fragments for master-detail navigation in that case.
Edit again
If you need a callback you can override onHiddenChanged like this:
public void onHiddenChanged(boolean hidden) {
if(hidden){// Do you stuff here}
}
As PPartisan mentioned you claimed that onHiddenChanged is never called.
The reason for that is because onHiddenChanged doesn't get called the first time an fragment is shown.
Called when the hidden state (as returned by isHidden()) of the fragment has changed. Fragments start out not hidden; this will be called whenever the fragment changes state from that.
To fix this: add this to your code:
FragmentTransaction mFragmentTransaction = getFragmentManager().beginTransaction();
if (f!= null) {
mFragmentTransaction .hide(f);
}
mFragmentTransaction.add(R.id.content_frame, f, null)
mFragmentTransaction.addToBackStack(null)
mFragmentTransaction.commit();
More on the on this SO thread
From the Android documentation:
void onStart () Called when the Fragment is visible to the user. This
is generally tied to Activity.onStart of the containing Activity's
lifecycle.
void onStop () Called when the Fragment is no longer started. This is
generally tied to Activity.onStop of the containing Activity's
lifecycle.
The correct way is using Fragment Lifecycle's methods.
This is get called then the fragment is changing visibility
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {}
Here i need to refresh the fragment from itself. So that i am going to using below code.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(this).attach(this).commit();
Above code is should be used in onstart() method or Oncreate() method for refreshing the current fragment from itself
From here you can under stand which method will call 1st and which after that,
So u can add this code where ever you want.
It should be onStart() You use the onCreateView() method in the fragment itself to define the xml layout that code will be using and the elements instantiated in that xml file.
On a more technical background, a fragment is always created in the onStart() method, hence taking precendence over the onCreateView() method. The reason is because in some cases, before displaying the fragment, the app needs to perform some background processes beforehand such as validation or getting data from the activity calling the fragment. This is done in the onStart() method before displaying the fragment.
In a Fragment's Lifecycle, the onAttach() method is called before the onCreate() method. I can't wrap my head around this. Why would you attach a Fragment first?
TL;DR:
In order to not break the design consistency amongst different UI components in android,the onCreate() method will have similar functionality across all of them.
When linking Containers to Contents like Window to Activity and Activity to Fragment a preliminary check needs to be done to determine the state of container.
And that explains the use and position of onAttach() in the fragment lifecycle.
Too short;Need longer:
The answer is in the archetype code itself,
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
Another example would be in Jake Wharton's ActionBarSherlock library.
Why would you want to use a method like onCreate() which is has the same purpose in an activity ,service.
The onCreate() is meant to handle issues with respect to that particular context creation.It does not make sense if onCreate() is used to check the state of its container.
The second reason that I can come determine is that a fragment is designed to be activity independent.The onAttach() provides an interface to determine the state/type/(other detail that matters to the fragment) of the containing activity with reference to the fragment before you initialize a fragment.
EDIT:
An activity exists independently and therefore has a self sustaining lifecycle.
for a fragment :
The independent lifecycle components(same as any other components):
onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()
The interaction based components:
onAttach()
onCreateView()
onActivityCreated()
onDestroyView()
onDetach()
from the documentation:
The flow of a fragment's lifecycle, as it is affected by its host
activity, (...) each successive state of the activity determines which
callback methods a fragment may receive. For example, when the
activity has received its onCreate() callback, a fragment in the
activity receives no more than the onActivityCreated() callback.
Once the activity reaches the resumed state, you can freely add and
remove fragments to the activity. Thus, only while the activity is in
the resumed state can the lifecycle of a fragment change
independently.
However, when the activity leaves the resumed state, the fragment
again is pushed through its lifecycle by the activity.
answering another question which came up in the comments:
Caution: If you need a Context object within your Fragment, you can call getActivity(). However, be careful to call getActivity() only when the fragment is attached to an activity. When the fragment is not yet attached, or was detached during the end of its lifecycle, getActivity() will return null.
The design philosophy states that a Fragment is designed for reuse. A fragment (by design) could(and should) be used across multiple activities.
The onCreate by definition is responsible to create a fragment.
Consider the case of orientation,your fragment could be:
- using different layouts in different orientations.
- applicable only in portrait orientation and not landscape
- To be used only on tables and mobile phones.
All these situations would require a check before the fragment is initialized from the android perspective(onCreate()) and the view inflated(onCreateView()).
Also consider the situation of a headless fragment.The onAttach() provides you the interface required for preliminary checks.
Because onAttach() assigns hosting activity to the Fragment. If it had been called after onCreate() then there would be no context for your fragment (getActivity() would return null) and you would not be able to do anything in onCreate() method without that context anyway.
Another fitting reason is that Fragment's lifecycle is similar to Activity's lifecycle. In Activity.onAttach() activity gets attached to its parent (a window). Similarly in Fragment.onAttach() fragment gets attached to its parent (an activity), before any other initialization is done.
This is related to retained fragments. Following Fragment setRetainInstance(boolean retain) documentation:
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.
Take a look at the source code (android.support.v4.app.FragmentManager, v21):
void moveToState(Fragment f,
int newState,
int transit,
int transitionStyle,
boolean keepActive) {
...
f.onAttach(mActivity);
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
mActivity.onAttachFragment(f);
}
if (!f.mRetaining) {
f.performCreate(f.mSavedFragmentState); // <- Here onCreate() will be called
}
...
}
Example
Case 1: not retained fragment or setRetainInstanceState(false)
Application is started. Fragment is added dynamically using FragmentManager or inflated from XML via setContentView().
onAttach() called after Activity super.onCreate() call - Activity is already initialised.
MainActivity﹕ call super.onCreate() before
MainActivity﹕ super.onCreate() returned
MainFragment﹕ onAttach() getActivity=com.example.MainActivity#1be4f2dd
MainFragment﹕ onCreate() getActivity=com.example.MainActivity#1be4f2dd
Configuration changed. Activity recreates fragments from saved state, fragments are added/attached from inside Activity super.onCreate() call:
MainActivity﹕ call super.onCreate() before
MainFragment﹕ onAttach() getActivity=com.example.MainActivity#2443d905
MainFragment﹕ onCreate() getActivity=com.example.MainActivity#2443d905
MainActivity﹕ super.onCreate() returned
Case 2: setRetainsInstanceState(true)
Application is started. Fragment is added dynamically using FragmentManager or inflated from XML via setContentView(). Same as above:
onAttach() called after Activity super.onCreate() call - Activity is already initialised.
MainActivity﹕ call super.onCreate() before
MainActivity﹕ super.onCreate() returned
MainFragment﹕ onAttach() getActivity=com.example.MainActivity#3d54a168
MainFragment﹕ onCreate() getActivity=com.example.MainActivity#3d54a168
Configuration changed.
Fragment onCreate() not called, but onAttach() still called - you need to know, that hosting Activity has changed. But still fragment is already created, so no onCreate() called.
MainActivity﹕ call super.onCreate() before
MainFragment﹕ onAttach() getActivity=com.example.MainActivity#d7b283e
MainActivity﹕ super.onCreate() returned
Two Points from Android developer Site hints at why onAttach() is called before onCreate() in case of Fragment Life cycle.
A fragment must always be embedded in an activity. Now this means for Fragment to EXIST, there has to be a "living" Activity.
Also, When you add a fragment as a part of your activity layout, it lives in a ViewGroup inside the activity's view hierarchy.
So Fragment must FIRST "attach" itself to activity to defines its own view layout
onCreateis Called to do initial creation of a fragment.
It is obvious that you will create something only when its pre-condition of creation is in place (and the pre-condition is A fragment must always be embedded in an activity, and it must be attached to its Activity)
I want to replace fragment and destroy previous.
Here my code :
FragmentManager manager = getFragmentManager();
FragmentTransaction newT = manager.beginTransaction();
newT.replace(R.id.activity_content currentFragment, CE_TAG);
newT.commit();
I read this article : http://sapandiwakar.in/replacing-fragments/
I've not put the fragment in back stack, but my fragement are not destroyed !
onPause(), onDestroy(), onStop() are never called.
Thanks.
Try
Fragment f = new YOurFragment();
fragmentTransaction.remove(f).commit();
Hope it helps
A fragment is maintained in memory even after it is no longer visible. If you call it back into existence, onCreateView is called and the visual part of the fragment is recreated but the actual object is reused. From the Docs:
onDestroy() = The final call you receive before your activity is
destroyed. This can happen either because the activity is finishing
(someone called finish() on it, or because the system is temporarily
destroying this instance of the activity to save space. You can
distinguish between these two scenarios with the isFinishing() method.
You should consider onDestroyView instead, or call finish if that suits you better.
http://developer.android.com/reference/android/app/Fragment.html
Try adding this line of code after committing the transaction.
getChildFragmentManager().executePendingTransactions();
Check this executePendingTransactions.
If you are replacing a fragment with the same tag, it may cause the issue of overlaping. Also, if your fragment container is a LinearLayout, it cannot update after replace (from my experience only).