Fragments pumped up with old data when returning to an activity that was stopped

Activity A has fragments. When it starts the plan of activity B, then when B.finish()

, A again executes onCreate()

.

But this time, although it A.onCreate()

has new PacksPagerAdapter

and new ViewPager

, the fragments are displayed with the old data.

I can see what onCreateView()

gets executed for each chunk, but it still has old arguments since it was static newInstance()

not called. Arguments are created when FragmentPagerAdapter is called getItem(position)

.

This is how it is implemented -

public class PackActivity extends Activity {
    ...
    PacksPagerAdapter mPacksPagerAdapter;
    ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mPacksPagerAdapter = new MyPagerAdapter(getFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mPacksPagerAdapter);
        mViewPager.setOffscreenPageLimit(PACK_PAGES - 1);

        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        actionBar.setTitle(...);
                    }
                });

    }
    ...
}

public class MyPagerAdapter extends FragmentPagerAdapter {
...
    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page.
        // Return a PlaceholderFragment (defined as a static inner class
        // below).
        return PackFragment.newInstance(myData);
    }
...
}

public class PackFragment extends Fragment {
...
    public static PackFragment newInstance(PackInfo pack) {
        PackFragment fragment = new PackFragment();

        Bundle bdl = new Bundle(2);
        bdl.putSerializable(EXTRA_PACK, pack);
        bdl.putInt(EXTRA_PACK_POSITION, pack.packNumber);
        fragment.setArguments(bdl);

        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View packView = inflater.inflate(R.layout.pack_fragment, container, false);

        // this has the old argument, since newInstance(...) wasn't called      
        PackInfo pack = (PackInfo) getArguments().getSerializable(EXTRA_PACK);
        ...

        return packView;
    }

...
}

      

Any idea why new fragments are not being created on the 2nd creation of Activity A?

Update - Lifecycle of Activity Fragments

The answer, as Tal said, is that the activity is being restored, so old fragments reattach rather than create new ones.

After spending a lot of time researching this, I've found that there are usually three scenarios for the lifecycle of activity fragments. Here are the scenarios, lifecycle and how to reload the old data chunk:

New Activity

Lifecycle: onCreate () ==> onResume () ==> Fragments are created and attached

No need to reboot.

Restored activity

Lifecycle: onCreate () ==> Fragments inflated with old data and reloaded ==> onResume ()

In onResume (), remove all fragments and create new ones, manually or automatically using an adapter -

        // Remove all fragments
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        for (int i = BuildConfig.PACK_PAGES - 1; i >= 0; i--) {
            Fragment f = findFragmentByPosition(i);
            if (f != null)
                fragmentTransaction.remove(f);
        }
        fragmentTransaction.commit();

        // This will force recreation of all fragments
        viewPager.setAdapter(packsPagerAdapter);

      

Renewed activity

Lifecycle: onResume ()

Same as restoring activity, deleting old fragments and re-creating.

Note. Some OS versions will always resume activity even when opening SettingsActivity for a few seconds, while other (older) versions will always resume.

+3


source to share


4 answers


my answer would be better if you post the fragment transaction you do in action A.

not sure if you know this or not - if activity A is recreated when it comes back from the back stack - that means it is restored from a previous instance state .

in this case, you shouldn't execute the transaction again, because - it is already being executed automatically using the super.onCreate () activity method. in fact if you do fragment fragmentation in this case - you will add the same fragment twice (2 instances)

you can see if onCreate()

instance state restore is currently being called if parameter savedInstanceState

is null or not.

My guess is that you are not validating savedInstanceState

and doing the transaction anyway.

if i am correct then the following change should fix the duplicate fragments issue:



instead:

public static class ActivityA extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        performFragmentTransaction();

}

      

records:

public static class ActivityA extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
           performFragmentTransaction();
        }
}

      

More information - http://developer.android.com/guide/components/fragments.html

+2


source


I think you should add your fragment to your view and commit.

write something like this in your "onCreate".



fragmentTransaction.add(R.id.container, YOUR_FRAGMENT);
fragmentTransaction.commit();

      

or replace the old one.

0


source


This is the declared behavior: Your fragments are restored .

Actually, it should also be noted that it is just an accident that causes A's activity to be recreated. It is possible that activity A still exists after B ends, which will not cause onCreate of A to be executed again.


Why is newInstance not being called?

This is because the fragments are actually in the FragmentManager of the killed activity. Therefore, they are restored when activity is recreated. Fragment tags are usually: "android: switcher:" + your_pager_id + ":" + your_fragment_position .

0


source


When the user walks away from the activity A

before B

, it FragmentPagerAdapter

strips the fragments in A

from the UI and does not destroy the instances so that they can be reused when the user returns to the A

last one.

I'm not sure why onCreate

from A

is called after completion B

. If you don't want the old fragments to be attached to the UI, instead you want them to be recreated, you need to explicitly destroy them.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mPacksPagerAdapter = new MyPagerAdapter(fragmentManager);

    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);

    // Remove the fragments if they already exist.
    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction currentTransaction = fragmentManager.beginTransaction();

    int count = mPacksPagerAdapter.getCount();
    for(int position = 0; position < count; position++) {
        long itemId = mPacksPagerAdapter.getItemId(position);
        // fragment name format maintained by adpater: "android:switcher:" + viewId + ":" + id
        String name = "android:switcher:" + mViewPager.getId() + ":" + itemId;
        Fragment fragment = fragmentManager.findFragmentByTag(name);
        if(fragment != null) {
            // if fragment instance exists, destroy it.
            currentTransaction.remove(fragment);
        }
    }
    // commit all the operations with state loss.
    currentTransaction.commitAllowingStateLoss();
    // immediately execute the operations
    fragmentManager.executePendingTransactions();

    // Rest of your code follows here.
    ....
}

      

0


source







All Articles