I have FragmentA and FragmentB.
I added FragmentA to an Activity using the add (not replace) fragment transaction. A button in FragmentA makes a callback to it's Activity which then makes an add fragment transaction to add FragmentB.
I update the title of the ActionBar with the value of a variable (which is fetched online) in FragmentA and FragmentB.
After the fragment transactions I outlined above, if I'm in FragmentB and I press the back button (now I'm in FragmentA), the title of the ActionBar is still that of FragmentB.
So I wanted to know which lifecycle methods are called on FragmentA when I'm coming from FragmentB so I can update the Actionbar from there.
I don't know if there is a method that is called when backstack is popped, but what you can do is overwrite onBackPressed in your Activity class that contains the fragments, call fragmentManager.popBackStackImmediate. This method returns a boolean, if it's true, then you went from fragmentB to fragmentA (or to any other previous fragment). You are in your activity class, so you can update your ActionBar anyway you'd like.
One more thing, if fragmentManager.popBackStackImmediate is true, don't call super.onBackPressed()!!!
onStart() method is clearly the adapted one. When comming from backstack, it will always be called.
Related
I'm using MVP in my project. I have an activity. Inside this activity I'm showing fragment. Fragment contains some data, edit text, buttons etc. From this fragment it is possible to navigate to another fragment. Here is my code for showing another fragment:
getParentFragmentManager()
.beginTransaction()
.replace(R.id.main_container, secondFragment)
.addToBackStack(null)
.commitAllowingStateLoss();
Next, when I try to go back from fragment 2 to fragment 1, my fragment one is re-created.The method onViewCreated() is called again with saveedInstanceState = null. Also in the onViewCreated() I call presenter.onCreate(savedInstanceState) and because of this, all requests that should be called when I first enter the fragment are re-called when I back to first fragment.
As far as I understand, when calling a .replace(container, fragment), I cannot avoid recreating the fragment view, but in this case, how can I save all my data in the presenter so that I do not re-execute all requests when returning to the fragment?
P.S. With .add() fragment is not recreated. But in my activity I have toolbar with title, and I don't need it to show in my second fragment. When I open my second fragment with .replace() toolbar is not showing, but when open with .add() toolbar is showing.
Use Fragment Result API :
For implemention this method set - setFragmentResultListener - in source fragment and also set - setResult() and finish() - in destination fragment
Note 1 : for having clean code i suggest you to use FragmentTransaction class in:
https://github.com/mahditavakoli1312/FragmentTransaction---mahdi-tavakoli
Note 2 : use Navigation for navigate betwin fragments and activities Instead tranastion
I have two fragments which share the same spot on a activity. When activity starts fragA is displayed. When you click a button from fragA it gets pushed to backstack and replaced by fragB. When a button from fragB is pressed the fragB is destroyed and fragA is poped from the backstack but it should also change some views based on what button from fragB was pressed (set the text for a textview for example). I used interfaces for fragment-activity communication. Everything goes well but the views from fragA don't want to change. I think I'm trying to change them while the fragment is in backstack.
#Override
public void onFragBClick(Bundle bundle) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragA = (FragA) fragmentManager.findFragmentByTag(TAG_FRAG_A);
if (fragA != null) {
fragmentManager.popBackStack(TAG_FRAG_A_BACKSTACK,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragA.onFragBSignalReceived(bundle);
}
}
This is the method that handles communication. Everything seems fine in logs, onFragBSignalReceived gets called, but I can't change the state of fragA's views in it. My guess is that when it gets called fragA is still on the backstack and that's why views are not updated. In that case how can I achieve this behavior in some other way?
You might want to use popBackStackImmediate() instead of popBackStack(). popBackStackImmediate() will perform the operation inside the method, whereas popBackStack() will queue the action and perform it later on.
I have some king of header in my activity, which says what kind of fragment is opened now. It's ok, when I'm just replacing one fragment by another, but I have a problem with handling backstack changes in onBackPressed. That's a part of my code in onBackPressed method:
Fragment fragment = fragmentManager.findFragmentById(R.id.main_fragment);
fragmentManager.popBackStack();
fragment = fragmentManager.findFragmentById(R.id.main_fragment);
in first row, fragment=FormFragment{41f01d58 #3 id=0x7f05005f}, and after calling popBackStack I have fragment=FormFragment{41f01d58 #3 id=0x7f05005f} again (but it should be another fragment, even not FormFragment instance).
Is there any way how to find out what fragment is popped from backstack after calling popBackStack?
First of all, usually you don't have to pop the fragment back stack yourself. If your activity is a FragmentActivity, its default onBackPressed() will do the work for you.
To update your header when the fragment is popped from the back stack, put the header update code in the fragment's onResume().
I have followed the ABS example of FragmentTabsPager, but I'm facing this problem:
Activity A has two fragments: F1, F2 which are added in onCreate() method of the A with use of the TabsAdapter.
Activity A has the option to refresh fragments which is done according to
http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
Activity A has the option to launch Activity B, which adds item to F1 (F1 thus, needs to be updated)
However, after finishing B, the fragments are not attached to A anymore. After some debugging, I found that the onCreate() method of A is called after finishing B with savedInstanceState containing this entry:
android:support:fragments=android.support.v4.app.FragmentManagerState$41bfffe0
My understanding is that FragmentActivity saved the fragments before launching B and after relaunching A, it tries to restore them. With a little of tracing I found that after finishing B, these actions are called:
Activity A: constructor called
Fragment F1: constructor called
Fragment F2: constructor called
Fragment F1: onAttach
Fragment F1: onCreate
Fragment F2: onAttach
Fragment F2: onCreate
Activity A: onCreate
Activity A: TabsAdapter created
TabsAdapter: addTab android.widget.TabHost$TabSpec#41d949f8
Fragment F1: constructor called
TabsAdapter: addTab android.widget.TabHost$TabSpec#41d965d0
Fragment F2: constructor called
Fragment F1: onActivityCreated
Fragment F1: onCreateLoader
Fragment F2: onActivityCreated
Fragment F2: onCreateLoader
Activity A: onStart
Fragment F1: onResume
Fragment F1: onCreateLoader
Fragment F2: onResume
Fragment F2: onCreateLoader
Activity B: onStop
Fragment F1: onLoadFinished
Fragment F2: onLoadFinished
There are 2 instances of each fragment, and the showing fragments are not attached to activity.
How can I solve this? What am I doing wrong? Maybe if there was a way how to get the restored fragments?
Thanks in advance
If I am understanding this correctly, here is what I would suggest:
Since Fragments F1 and F2 live in Activity A, Activity B should not create, or attempt to interact with either Fragment.
Have Activity A start Activity B using startActivityForResult, and have B pass back the item (to be added to Fragment F1) to A.
Activity A should handle sending the new item to Fragment F1 using an interface (like you've done).
Upon receiving the new item (in your interface method) from Activity A, Fragment F1 should then update its data and refresh its Views.
Another thing to note, ensure that your Activity A only adds your Fragments once in onCreate, it can use the savedInstanceState to know if it is being recreated or if it's the first creation of it. See http://developer.android.com/training/basics/fragments/fragment-ui.html.
Edit
Ah now I see more of what you are asking. There are several ways you can go here.
Use the FragmentManager and the tag trick to get the Fragments out of the ViewPager, and update them as needed.
This is slightly more dangerous as it will return Fragments that may not be in onResume and need to be checked before being interacted with.
Decouple the model from the controller, as in put your data into a static singleton, SQLite DB, or even preferences. This would allow other portions of the app to access and edit the data, without the need of passing it around.
In onResume, your Fragments would then need to check and update their data, in case it had been changed.
Your Activity will also need to give them a refresh signal via an interface method if the Fragments are already in onResume when the change occurs.
OR, use a Loader in your Fragments to monitor the data set and have it autoupdate the Fragment's UI via interface callbacks.
I am very confused between these functions and their purposes. What I have observed that using replace() replaces the existing fragment with a new one. We can use addToBackStack(null) to put that fragment in back stack so we can go back to the previously shown fragment. Now when a fragment is added (or replaced) - onAttach() -> onCreate() etc.... methods of the fragment are called in order.
Now when we call remove() on the fragment from our activity, which functions of the fragment are called and in which order?
What does attach() and detach() do? Does detach() remove the fragment? And when these two attach() and detach() are used, which functions of the fragment are called and in which order??
Also, what happens on popBackStack()?? I mean which functions are called when we use popBackStack()on the fragment from our activity??
And when does onDestroy() called??
Thank you.
Now when we call remove() on the fragment from our activity, which functions of the fragment are called and in which order?
Look at http://developer.android.com/reference/android/app/Fragment.html .
The order is: onPause(), onStop(), onDestroyView(), onDestroy(), onDetach()
What does attach() and detach() do? Does detach() remove the fragment? And when these two attach() and detach() are used, which functions of the fragment are called and in which order??
attach() and detach() is respectively associates or detaches the Fragment with/from the Activity. When attaching the Fragment, the onAttach() lifecycle method is called, when detaching, the onDetach() lifecycle method is called in the Fragment. For more information look at the link above.
Also, what happens on popBackStack()?? I mean which functions are called when we use popBackStack()on the fragment from our activity??
If the Fragment hasn't been destroyed, then on popBackStack() the onStart() and onResume() methods are called. If the Fragment has been destroyed previously, then the lifecycle methods will be called starting from onAttach(). It's the same as, when you press the back button on Activities.
Just a note on popBackStack(). It doesn't pop a fragment, it pops a fragment transaction. So whatever the last fragment transaction was is reversed. If you were displaying a FragmentA and your transaction was:
fragmentTransaction.replace(R.id.your_layout, fragmentB);
fragmentTransaction.addToBackStack(null);
It would replace FragmentA with FragmentB, and add that transaction (not the fragment) to the back stack. If you then hit the back button, it pops the back stack and gets the transaction, which was "replace this FragmentA with a FragmentB". It then reverses that transaction. Backwards, the instruction is to replace whatever the current fragment is with FragmentA. If the original FragmentA still exists, it uses that one. If it's been destroyed, it makes a new one.
Suppose fragment A and fragment B was added to a container with the following steps:
1. Added fragment A => .replace(R.id.container, fragmentA) => addToBackStack(null)
2. Added fragment B => .replace(R.id.container, fragmentB) => addToBackStack(null)
3. Removed fragment B => fragmentManager.popBackStack();
Callbacks when fm.popBackStack() is called:
FragmentB: onPause()
FragmentB: onStop()
FragmentB: onDestroy()
FragmentB: onDetach()
FragmentA: onCreateView()
FragmentA: onViewCreated()
FragmentA: onActivityCreated()
FragmentA: onStart()
FragmentA: onResume()
Explanation: Why while removing and destroying fragment B using popBackStack(), fragment A view was created again and resumed?
Ans: When you added fragment B, you used replace() and addToBackStack(), so all the fragments were removed from the container, and fragment B was added to the container. And, also this transaction was recorded in the Back stack. So, when fm.popBackStack() is called, first the transaction is popped out from the back stack and so the operations reverted itself, therefore fragment b is removed from the container and destroyed. And all other fragments get added, for our case fragment A's view is added to the container. Also noted that fragment A's onAttach & onCreate() is not called because it has already been created & attached to the MainActivity earlier.
Back press on fragment B does the same thing:
If you press the back button, it calls fm.popBackStack() and pops the transaction.