So I have a problem that I can't seem to solve. I have a ViewPager in one of my activities, say MainActivity. I am implementing all the required methods to save and retrieve instance state when the activity gets killed in the background. But when the activity tries to restore its state, the fragments are restored but they are not attached to the viewpager so all I get is a white screen.
Here is the relavant code:
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//..
if (savedInstanceState==null) {
setupViewPager();
}
}
private void setupViewPager() {
mAdapter = new ViewPagerAdapter(getSupportFragmentManager());
mAdapter.addFrag(FirstFragment.newInstance(mFeedItem), "INFO");
//Note: mFeedItem is obtained from the intent and I have verified
// that it is properly restored.
mAdapter.addFrag(SecondFragment.newInstance(mFeedItem), "SERVICES");
mViewPager.setAdapter(mAdapter);
mTabLayout.setupWithViewPager(mViewPager);
}
ViewPagerAdapter.java
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
FirstFragment.java
public static FirstFragment newInstance(Workshop item) {
FirstFragment f = new FirstFragment();
f.mItem = item;
return f;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("feed_item",Workshop.packToGson(mItem));
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_item_detail_info, container, false);
if (savedInstanceState!=null) {
mItem = Workshop.extractGson(savedInstanceState.getString("feed_item"));
}
return v;
}
So if I navigate to another activity and then the MainActivity
gets killed in the background ( I am using the Don’t Keep Activities setting to test this), this happens:
1) The Activity gets restored properly, no issues there.
2) The onCreateView
of the fragments are called, with the savedInstanceState
intact.
3) But, the ViewPager and Adapter in my Activity are null
. The fragments dont seem to get attached back to the adapter/viewpager.
So what am I missing here? Am I supposed to do anything to properly restore the fragments?
I am able to solve the issue quickly by replacing this in my MainActivity
:
if (savedInstanceState==null) {
setupViewPager();
}
with just setupViewPager();
, so that a new adapter and fragments are created irrespective of whether it is restoring or launching for the first time. But that comes with the drawback of resetting the state of the fragments. Also, when I do that, I find that there are two instances of each fragment, one which is restored and a new one, with only the new instances actually displayed. So I dont believe that it is the best approach.
You can create swipe views using AndroidX's ViewPager widget. To use ViewPager and tabs, you need to add a dependency on ViewPager and on Material Components to your project. To insert child views that represent each page, you need to hook this layout to a PagerAdapter .
This function is deprecated.
You can't use ViewPager to swipe between Activities . You need to convert each of you five Activities into Fragments , then combine everything in one FragmentActivity with the Adapter you use with ViewPager .
Firstly set viewpager adapter to null then recreate the adapter and set i to it to viewpager. Show activity on this post. Define which message which is needed to update. Write below code in the Fragment which is needed update.
By destroying the Activity
you also destroy every instance field. So you have to re-instantiate the ViewPager
and Adapter
. There are two scenarios you have to keep in mind.
FragmentStatePagerAdapter
saves/restores Fragments
with the FragmentManager
Fragments
inside the Fragment
The first point is the reason why you have two instances of each Fragment
. In order to fix this you can get the stored Fragment by its ID. See this grepcode FragmentPagerAdapter
(same goes for StateAdapter
)
private static String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
Instead of instantiating a Fragment
in setupViewPager
every time - you get it from the FragmentManager
first e.g.
mAdapter = new ViewPagerAdapter(getSupportFragmentManager());
int fragmentCount = 2; // save value if it's a arbitrary list of fragments
for (int index = 0; i < fragmentCount; i++) {
FirstFragment firstFragment = (FirstFragment) getSupportFragmentManager().findFragmentByTag(makeFragmentName(R.id.view_pager, index));
if (firstFragment == null) {
firstFragment = FirstFragment.newInstance(mFeedItem);
}
mAdapter.addFrag(firstFragment, "someTitle");
}
The above is an example on how to restore previous saved Fragments
from the FragmentManager
. You probably have to adjust the cases where you have different types of BaseFragments
and so on. Furthermore you might want to save the Fragment
title names and the total count to restore them.
The second point is that you have to restore the current Fragment
state from the Fragment
itself. For that your Fragment
has the lifecycle methods. See this SO topic about that Once for all, how to correctly save instance state of Fragments in back stack?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With