FragmentTabsPager - tabs issue - android

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.

Related

Which lifecycle methods are called when a fragment is popped off backstack

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.

How to restore fragment views state after returning from back stack

I have Fragment which I replace by another one. I put transaction to backstack so I can move back later. If I press back button saveInstanceState Bundle of restored Fragment is null in it's methods cause saveInstanceState method of Fragment is actually called when parent Activity instance destroyed. So how I must restore Fragment state after returning it from backstack?
This problem was mostly related to ListViews. I have found a solution in more correct managing of adapter data. I had local mAdapter variable in my Fragment which was created, populated with data and set to ListView in onResume() method of my Fragment. I have found solution in moving this code into onActivityCreated() method.

My callback called before onResume and cannot change layout

I really need your help here.
I have two Fragments:
1. Fragment A
2. Fragment B
One Interface
1. onSkillsSelectedListener ( method onDoneClicked )
Fragment A implements onSkillsSelectedListener and when "DONE" button is called in Fragment B, i call onDoneClicked() , and Fragment B is destroyed.
Now method onDoneClicked in Fragment A is called before even OnResume in Fragment A is called so i cannot make any changes in my Layout.
How to fix this issue?
The fragments onResume() or onPause() will be called only when the Activities onResume() or onPause() is called. They are tightly coupled to the Activity.
http://developer.android.com/guide/components/fragments.html#Lifecycle
You need to find another way to implement this.
I FIX IT
Just changed the way i called my Fragment B
from replace to add
So now Fragment A is not even Paused and callback is working!
Cheers!

Call Fragments onCreateView in context with Tabs

I have 2 Tabs and 2 Corresponding Fragments. On calling the LAUNCH Activity both Tabs were added and then the first one added will be shown. Thus the first Fragments onCreateView is called the second Fragments ones not.
In my case this is an issue because the first Fragment has to call methods on the second Fragment. Inside the second Fragment there is an Objectreference which will be set by calling the onCreateView in the second Fragment.
Therefore I used following code snippet to solve this
actionBar.setSelectedNavigationItem(1);
actionBar.setSelectedNavigationItem(0);
It works but in my opinion there must be another possibility to solve this issue. Like calling the onCreateView of the second Fragment?
Here is the relevant code snippet. The listener is implemented as in android-dev Sample only with small changes not affecting my issue.
simplexFragment corresponds to the first Fragment
graphicFragment corresponds to the second Fragment
// adds two tabs
actionBar.addTab(actionBar.newTab().setText("Input").setTabListener(new TabListener(null, "input_fragment")));
graphicFragment = new GraphicFragment();
actionBar.addTab(actionBar.newTab().setText("Graphic").setTabListener(new TabListener(graphicFragment, "graphic_fragment")));
simplexFragment.setGraphics(graphicFragment); // sets the internal reference!
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// selects the Tab so the GraphicFragments onCreateView will be called
actionBar.setSelectedNavigationItem(1);
actionBar.setSelectedNavigationItem(0);
Thanks for support.
In my case this is an issue because the first Fragment has to call methods on the second Fragment.
This is not how Fragments are meant to work. The idea is a Fragment should be self-contained and re-usable and one Fragment shouldn't know that another exists (or at least shouldn't rely the existence any other Fragment).
For example, suppose you have 3 Fragments and ActivityA uses FragmentA and FragmentB but you have another Activity (ActivityB) which uses FragmentA and FragmentC. In that case, FragmentA doesn't know what the other Fragment is (B or C) and shouldn't even expect there to be another Fragment at all.
The way to achieve what you want is to use callback methods on the Activity and have it perform the actions on any other Fragments (if they exist). It can do this by either calling public methods on the other Fragments or by passing data in the 'arguments' Bundle when it creates the other Fragments.

Fragment methods: attach(), detach(), remove(), replace(), popBackStack()

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.

Categories

Resources