安卓:Viewpager和FragmentStatePageAdapter

9
我正在设计一个应用程序,允许用户在ViewPager中翻转多个页面。我一直在努力尝试弄清楚如何在屏幕上不再可见时从页面中删除Fragment实例、将其缓存(例如到HashMap)并恢复它,以便当用户翻回该页面时,视图和其他所有内容都将处于与删除之前相同的状态。例如,我的第一页是一个登录屏幕,在成功登录时会使该特定页面上的某些布局元素可见/不可见。当我向前翻了足够多的页面,然后翻回第一页时,布局会重置。这对我的另一个页面来说更成为问题,该页面包含一个巨大的横向/纵向滚动数据网格,我在后台使用线程进行绘制。我使用进度对话框通知用户加载进度,但每次加载时都很麻烦。
所以我做了一些研究......
我浏览了FragmentStatePageAdapter的源代码,在destroyItem()回调中,被删除的Fragment实例的状态被保存到一个ArrayList中。当在instantiateItem()回调中创建新的Fragment实例时,如果项目的实例不存在(他们通过使用ArrayList进行跟踪),则创建一个新的Fragment实例,并使用相应的Fragment.SavedState数据初始化其保存的状态。不幸的是,这些数据不包括视图所在的状态,尽管我注意到对于具有GridView/ListView的页面,视图的状态会以某种方式被恢复(如果我滚动到某个随机位置,翻了几页然后回来,它不会被重置)。
根据API的说法:
“保存的状态不能包含对其他片段的依赖关系——也就是说,它不能使用putFragment(Bundle, String, Fragment)来存储片段引用,因为当稍后使用此保存的状态时,该引用可能无效。同样,片段的目标和结果代码也不包括在此状态中。”
作为Android的新手,我不太确定我是否理解了最后一句话。
也就是说,有没有办法缓存View状态?如果没有,我想我将继续保留所有fragment页面在内存中。
5个回答

4
我遇到了同样的问题,并通过实现这两个函数来解决它。
    public void onSaveInstanceState (Bundle outState)
    public void onActivityCreated (Bundle savedInstanceState)

在我想要保存的片段上,您应该在第一个函数中将您需要恢复视图的日期保存到Bundle中(在我的情况下,我有一堆旋转器,所以我使用了一个int数组来保存它们的位置)。第二个函数是在恢复您的片段时调用的函数,您需要在其中实现恢复过程。

我希望这可以帮助您。我还让我的适配器继承自FragmentStatePageAdapter,但我不确定这是否是必需的。


3
如果你仅使用FragmentPagerAdapter,那么需要继承自FragmentStatePagerAdapter,否则onSaveInstanceState方法将不会被调用。 - Scott

2

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">
    <TextView android:text="Page 1" android:id="@+id/textViewHeader"
        android:layout_width="fill_parent" android:layout_height="wrap_content"
        android:gravity="center" android:padding="10dip" android:textStyle="bold"></TextView>
    <android.support.v4.view.ViewPager
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        android:id="@+id/viewPager" />
</LinearLayout>

设置ViewPager

ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
MyPagerAdapter adapter = new MyPagerAdapter(this);
viewPager.setAdapter(adapter);

PagerAdapter(页面适配器)
@Override
public void destroyItem(View view, int arg1, Object object) {
         ((ViewPager) view).removeView((View)object);
}
@Override
public int getCount() {
          return views.size();
}
@Override
public Object instantiateItem(View view, int position) {
           View view = views.get(position);
           ((ViewPager) view).addView(view);
           return view;
}
@Override
public boolean isViewFromObject(View view, Object object) {
           return view == object;
}

点击这里查看更多细节:ViewPager示例


1

通过查看各种文档片段,我最好的猜测是您创建的视图没有附加ID。假设片段的保存状态是从Fragment.onSaveInstanceState创建的,则片段将自动保存具有ID的任何视图状态。如果您从布局文件创建了默认ID与ListView/GridView相关联,那么您可能已经在这些视图中设置了一个默认ID。您还可以通过调用setId将ID与视图关联起来。

此外,对于您的自定义填充片段,您还可能需要在onSaveInstanceState中进行一些自定义操作。


0

当我使用PagerSlidingTabStrip并使用FragmentPagerAdapter实例时,我也遇到了这个问题,但切换到FragmentStatePagerAdapter肯定有效。

然后我使用onSaveInstanceState()保存状态。


0
这是我在 PagerAdapter 中实现缓存的一个例子。填充缓存后,所有未来的视图请求都将从缓存中提供,只有数据会被替换。
public class TestPageAdapter extends PagerAdapter{

private int MAX_SIZE = 3;
private ArrayList<SoftReference<View>> pageCache = new ArrayList<SoftReference<View>>(3);


public TestPageAdapter(Context context){
    // do some initialization
}

@Override
public int getCount() {
    // number of pages
}

private void addToCache(View view){
    if (pageCache.size() < MAX_SIZE){
        pageCache.add(new SoftReference<View>(view));
    } else {
        for(int n = (pageCache.size()-1); n >= 0; n--) {
            SoftReference<View> cachedView = pageCache.get(n);
            if (cachedView.get() == null){
                pageCache.set(n, new SoftReference<View>(view));
                return;
            }
        }
    }
}

private View fetchFromCache(){
    for(int n = (pageCache.size()-1);  n>= 0; n--) {
        SoftReference<View> reference = pageCache.remove(n);
        View view = reference.get();
        if (view != null) {
            return view;
        }
    }
    return null;
}

@Override
public Object instantiateItem(View collection, int position) {
    View view = fetchFromCache();
    if (view == null) {
        // not in cache, inflate manually
        LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.page, null);
    } 
    setData(view, position);
    ((ViewPager) collection).addView(view, 0);
    return view;         
}

private void setData(View view, int position){
    // set page data (images, text ....)
}

public void setPrimaryItem(ViewGroup container, int position, Object object) {
    currentItem = (View)object;
}

public View getCurrentItem() {
    return currentItem;
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == ((View) object);
}

@Override
public void destroyItem(View collection, int arg1, Object view) {
    ((ViewPager) collection).removeView((View) view);
    addToCache((View) view);
}

}

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