Android Viewpager fragments refreshed when swiped

孤者浪人 提交于 2020-06-26 04:14:31

问题


I am new in Android and I don't really understand why a Fragment's content which was added dynamically (for example some image which was added after a button click) is disappearing after scrolling some count of Fragments and then come back.

There is really simple code Activity and Fragment:

public class MyActivity extends FragmentActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
        final CustomAdapter adapter = new CustomAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);
    }

    class CustomFragment extends Fragment {

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment, container, false);
        }

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            getView().findViewById(R.id.clickMeButton).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    getView().findViewById(R.id.image).setVisibility(View.VISIBLE);
                }
            });
        }

    }

    class CustomAdapter extends FragmentStatePagerAdapter {

        private List<CustomFragment> fragments = Arrays.asList(
            new CustomFragment(),
            new CustomFragment(),
            new CustomFragment()
        );

        public CustomAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int i) {
            return fragments.get(i);
        }

        @Override
        public int getCount() {
            return fragments.size();
        }
    }

}

and appropriate xmls:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent">

    <android.support.v4.view.ViewPager
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/viewPager" />

</LinearLayout>

fragment.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

    <Button
            android:id="@+id/clickMeButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="click me"/>

    <ImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_launcher"
            android:visibility="gone"/>

</LinearLayout>

Logic is simple. On each Fragment I can click on a Button and as result an image appears.

And it works. But ...

When I show image on the first fragment, then scroll to the third one and come back to first one again image is gone.

What should I do to prevent this ? Should I somehow save state of visibility?


回答1:


This is happening because FragmentStatePagerAdapter releases the memory associated with a Fragment when it is scrolled out of view. From the docs:

When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.

You can try one of the following four options:

1. Since you have a small number of pages, you can use FragmentPagerAdapter instead of FragmentStatePagerAdapter. FragmentPagerAdapter holds onto the created Fragments and does not destroy them on swipe.

2. In your Fragment, store a boolean in a SharedPreference and set (or clear) its value when you make the image visible or invisible. Then in the onResume() method of your Fragment, make the image visible or invisible based on the value of the SharedPreference.

3. In the onCreate() of your Fragment, call setRetainInstance(true);.

4. If the number of fragments is fixed & relatively small, then in your onCreate() add the following code:

mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit);         /* limit is a fixed integer*/



回答2:


Whats happening is

Since you are using adapter there may be a number of fragments active at a time like 3 or 4 for example.

Adapter will render the views dynamically to reduce the memory usage. In your case

Fragment 1 -> Fragment 2 - > Fragment 3

Let the active fragment be 3 now, So Fragment 1 may be removed from memory when you scroll back , it will redraw the fragment by

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment, container, false);
}

So the image is still invisible and in its initial stage.

Answer

Set a flag to identify the status of the image and use it in onCreateView() to make it visible or invisible.

UPDATE

mViewPager = (ViewPager)findViewById(R.id.viewPager);
mViewPager.setOffscreenPageLimit(yourLimit);

yourLimit is the number of fragments you want to keep alive which is not in screen currently.

NOTE: This is memory intensive.




回答3:


save the visibility of image in onSaveInstance method of your fragment class CustomFragment. Override onSaveInstanceState in the fragment activity class onSaveInstanceState call super.onSaveInstanceState(bundle) in that overridden method

     @Override
    public void onSaveInstanceState(Bundle outState) {

       super.onSaveInstanceState(outState);
       outState.putString("visibility", visibility);
      }

Then you can retain the state in the onActivityCreated method of your fragment class CustomFragment

int visibility = View.INVISIBLE;
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if(savedInstanceState!=null)
            visibility = savedInstanceState.getInt("visibility");
        getView().findViewById(R.id.image).setVisibility(visibility);
        getView().findViewById(R.id.clickMeButton)
        .setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getView().findViewById(R.id.image).setVisibility(View.VISIBLE);
            }
        });
    }



回答4:


mViewPager.setOffscreenPageLimit(limit);

It worked for me thanks ! I had a viewpager with 3 fragments and a recyclerview in the first one. When i clicked on the last one my recyclerview disappeared..

Not checked yet about performance



来源:https://stackoverflow.com/questions/24217621/android-viewpager-fragments-refreshed-when-swiped

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!