当滑动时刷新Android Viewpager片段

3

我是Android的新手,我不太明白为什么动态添加的Fragment内容(例如在单击按钮后添加的一些图像)在滚动一定数量的Fragment之后消失,然后再次出现。

这里有一个非常简单的ActivityFragment代码:

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>

逻辑很简单。在每个片段上,我可以点击一个按钮,结果会出现一张图片。

这也起作用。但是...

当我在第一个片段中显示图像,然后滚动到第三个片段并再次回到第一个片段时,图像就消失了。

我应该怎么做来防止这种情况?我是否应该以某种方式保存可见性状态?

4个回答

7
这是因为当滑出屏幕时,FragmentStatePagerAdapter会释放与 Fragment 关联的内存。来自文档

当页面对用户不可见时,它们的整个片段可能会被销毁,只保留该片段的保存状态。这使得分页器每个访问过的页面相关联的内存都比FragmentPagerAdapter少得多,但代价是在页面之间切换时可能需要更多的开销。

你可以尝试以下四种选项之一: 1.由于页面数量较少,您可以使用 FragmentPagerAdapter 而不是 FragmentStatePagerAdapter 。 FragmentPagerAdapter 会保留创建的 Fragment 并在滑动时不会销毁它们。 2. 在您的 Fragment 中,在 SharedPreference 中存储一个布尔值,并在使图像可见或不可见时设置(或清除)其值。然后在您的 Fragment 的 onResume()方法中,根据 SharedPreference 的值将图像设置为可见或不可见。 3. 在您的 Fragment 的 onCreate()中,调用 setRetainInstance(true); 。 4. 如果片段的数量是固定且相对较小的,则在您的 onCreate()中添加以下代码:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit);         /* limit is a fixed integer*/

谢谢您的回复。我已经尝试了1和3个项目(除第2个之外),但结果是相同的。是否有其他方法可以存储片段而不从内存中删除?我需要实现类似于Web浏览器中的选项卡的东西。因此,我将使用WebView。当然,我可以在SharedPreferences页面中存储用户选择的页面。但是它每次都会加载该页面。这真的不正确。因此,我需要确切地保留片段在内存中。 - vetalitet

3

正在发生的事情是:

由于您使用了适配器,可能会同时有多个片段处于活动状态,例如3或4个。

适配器会动态地呈现视图以减少内存使用。在您的情况下:

Fragment 1 -> Fragment 2 -> Fragment 3

现在让活动片段是3,所以当您向后滚动时,Fragment 1 可能会从内存中移除,这将通过重新绘制该片段来实现。

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

因此,这张图片仍然是不可见的,并处于初始状态。

答案:

设置一个标志来识别图片的状态,并在onCreateView()中使用它来使图片变为可见不可见

更新:

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

yourLimit是指您想保持活动状态的片段数,这些片段目前不在屏幕上显示。

注意:这会占用大量内存。


谢谢回复,但也许有一些方法可以在不重新创建的情况下精确地保留片段在内存中吗?我需要使用WebView组件来实现类似于Web浏览器中的选项卡的东西。但是片段重建将一直加载页面。 - vetalitet

1
在您的片段类CustomFragment的onSaveInstance方法中保存图像的可见性。在片段活动类中重写onSaveInstanceState方法,在该重写方法中调用super.onSaveInstanceState(bundle)。请注意,不要改变已有的HTML标签。
     @Override
    public void onSaveInstanceState(Bundle outState) {

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

然后,您可以在片段类CustomFragment的onActivityCreated方法中保留状态。
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);
            }
        });
    }

谢谢您的回复,但也许有一些方法可以在不重新创建片段的情况下将片段保留在内存中。 - vetalitet
如果您有固定且相对较少的片段,请使用以下代码:viewPager.setOffscreenPageLimit(numberOfFragment) - Pr38y

1

mViewPager.setOffscreenPageLimit(limit);

谢谢,它对我有用!

我有一个带有3个片段和第一个片段中的recyclerview的viewpager。当我点击最后一个片段时,我的recyclerview消失了。

关于性能还没有检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接