【问题标题】:Android: Viewpager and FragmentStatePageAdapterAndroid:Viewpager 和 FragmentStatePageAdapter
【发布时间】:2011-10-17 23:46:48
【问题描述】:

我正在设计一个允许用户在 ViewPager 中的多个页面之间切换的应用程序。我一直在努力弄清楚如何在屏幕上不再可见时从页面中删除 Fragment 实例,将其缓存(例如,HashMap),然后将其还原,以便当用户翻回该页面,其中的视图和其他所有内容将处于与删除之前相同的状态。例如,我的第一个页面是一个登录屏幕,它使该特定页面上的某些布局元素在成功登录时可见/不可见。当我向前翻了足够多的页面然后翻回第一页时,布局被重置。对于我的另一个页面来说,这成为一个更大的问题,其中包含一个巨大的水平/垂直滚动数据网格,我在初始化时使用后台线程进行绘制。我使用进度对话框来通知用户加载进度,每次我必须加载它时都会变得非常烦人。

所以我做了一些研究......

我浏览了 FragmentStatePageAdapter 的源代码,在 destroyItem() 回调中,被删除的 Fragment 实例的状态被保存到一个 ArrayList 中。当在 instantiateItem() 回调中创建 Fragment 的新实例时,如果项目的实例尚不存在(它们通过使用 ArrayList 来跟踪这一点),则会创建一个新的 Fragment 实例并保存其状态使用相应的 Fragment.SavedState 数据进行初始化。不幸的是,这些数据不包括视图所处的状态,尽管我注意到对于具有 GridView/ListView 的页面,视图的状态以某种方式恢复(如果我滚动到某个随机位置,翻了几页然后回来,它不会被重置)。

根据 API:

保存的状态不能包含对其他片段的依赖—— 那就是它不能使用 putFragment(Bundle, String, Fr​​agment) 来存储 片段引用,因为当这个引用可能无效时 保存状态稍后使用。同样,片段的目标和结果 代码不包含在此状态中。

作为一个 Android 新手,我不太确定我是否理解最后一句话。

话虽如此,有没有办法缓存视图状态?如果没有,我想我会继续将所有片段页面留在内存中。

【问题讨论】:

    标签: android caching adapter pager fragment


    【解决方案1】:

    我遇到了同样的问题,通过实现这两个功能解决了

        public void onSaveInstanceState (Bundle outState)
        public void onActivityCreated (Bundle savedInstanceState)
    

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

    我希望这会有所帮助。我还让我的适配器从 FragmentStatePageAdapter 继承,但我不确定这是强制性的。

    【讨论】:

    • 需要继承自FragmentStatePagerAdapter,如果只使用FragmentPagerAdapter则不会调用onSaveInstanceState。
    【解决方案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;
    }
    

    查看这里了解更多详情view pager example

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        这是我如何在 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);
        }
        
        }
        

        【讨论】:

          【解决方案5】:

          我在使用 PagerSlidingTabStrip 并使用 FragmentPagerAdapter 的实例时也遇到了这个问题,切换到 FragmentStatePagerAdapter 确实有效。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-05-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多