Android 如何实现PagerAdapter的视图回收机制?

Android 如何实现PagerAdapter的视图回收机制?,android,android-viewpager,android-pageradapter,convertview,Android,Android Viewpager,Android Pageradapter,Convertview,我有一个寻呼机适配器,它可以膨胀表示日历的复杂视图 每年充气大约需要350毫秒 为了提高性能,我想实现循环视图的ListView数组适配器中存在的相同机制(getView()中的convertView参数) 这是我当前从适配器获得的getView() @Override protected View getView(VerticalViewPager pager, final DateTileGrid currentDataItem, int position) { mInflater

我有一个寻呼机适配器,它可以膨胀表示日历的复杂视图

每年充气大约需要350毫秒

为了提高性能,我想实现循环视图的
ListView
数组适配器中存在的相同机制(
getView()
中的
convertView
参数)

这是我当前从适配器获得的
getView()

@Override
protected View getView(VerticalViewPager pager, final DateTileGrid currentDataItem, int position)
{
    mInflater = LayoutInflater.from(pager.getContext());

        // This is were i would like to understand weather is should use a recycled view or create a new one.
    View datesGridView = mInflater.inflate(R.layout.fragment_dates_grid_page, pager, false);


    DateTileGridView datesGrid = (DateTileGridView) datesGridView.findViewById(R.id.datesGridMainGrid);
    TextView yearTitle = (TextView) datesGridView.findViewById(R.id.datesGridYearTextView);
    yearTitle.setText(currentDataItem.getCurrentYear() + "");
    DateTileView[] tiles = datesGrid.getTiles();

    for (int i = 0; i < 12; i++)
    {
        String pictureCount = currentDataItem.getTile(i).getPictureCount().toString();
        tiles[i].setCenterLabel(pictureCount);
        final int finalI = i;
        tiles[i].setOnCheckedChangeListener(new DateTileView.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(DateTileView tileChecked, boolean isChecked)
            {
                DateTile tile = currentDataItem.getTile(finalI);
                tile.isSelected(isChecked);
            }
        });
    }

    return datesGridView;
}
@覆盖
受保护的视图getView(VerticalViewPage寻呼机,最终DateTileGrid currentDataItem,int位置)
{
mInflater=LayoutInflater.from(pager.getContext());
//这是我想了解的天气是应该使用循环视图还是创建一个新视图。
View datesGridView=mInflater.inflate(R.layout.fragment\u dates\u grid\u页面,寻呼机,false);
DateTileGridView datesGrid=(DateTileGridView)datesGridView.findViewById(R.id.datesGridMainGrid);
TextView yearTitle=(TextView)datesGridView.findViewById(R.id.datesGridYearTextView);
yearTitle.setText(currentDataItem.getCurrentYear()+);
DateTileView[]tiles=datesGrid.getTiles();
对于(int i=0;i<12;i++)
{
字符串pictureCount=currentDataItem.getTile(i).getPictureCount().toString();
平铺[i].setCenterLabel(pictureCount);
最终int finalI=i;
tiles[i].setOnCheckedChangeListener(新的DateTileView.OnCheckedChangeListener(){
@凌驾
检查更改后的公共无效(DateTileView-tileChecked,boolean-isChecked)
{
DateTile=currentDataItem.getTile(最终);
瓷砖。已选定(已检查);
}
});
}
返回日期RIDVIEW;
}
有没有实现这种行为的指针或方向?
特别是,我如何在适配器中知道屏幕上有一个
DateTileGridView
正在被刷走,这样我就可以将它保存在内存中,以便下次再使用它。

所以我已经找到了答案

  • 覆盖
    destroitem(视图组容器、int位置、对象视图)
    ans保存缓存视图
  • 创建一个单独的方法,看看是否有机会使用回收视图,或者是否应该为新视图充气
  • 记住,一旦使用了回收的视图,就要将其从缓存中删除,以避免相同的视图将相同的视图附加到寻呼机上
  • 这是密码。。我使用了一个视图堆栈来缓存从寻呼机中删除的所有视图

    private View inflateOrRecycleView(Context context)
    {
    
        View viewToReturn;
        mInflater = LayoutInflater.from(context);
        if (mRecycledViewsList.isEmpty())
        {
            viewToReturn = mInflater.inflate(R.layout.fragment_dates_grid_page, null, false);
        }
        else
        {
            viewToReturn = mRecycledViewsList.pop();
            Log.i(TAG,"Restored recycled view from cache "+ viewToReturn.hashCode());
        }
    
    
        return viewToReturn;
    }
    
    @Override
    public void destroyItem(ViewGroup container, int position, Object view)
    {
        VerticalViewPager pager = (VerticalViewPager) container;
        View recycledView = (View) view;
        pager.removeView(recycledView);
        mRecycledViewsList.push(recycledView);
        Log.i(TAG,"Stored view in cache "+ recycledView.hashCode());
    }
    

    不要忘记在适配器构造函数中实例化堆栈。

    我是这样做的。首先创建抽象软缓存类:

    public abstract class SoftCache<T> {
        private Stack<Reference<T>> mRecyclingStack;
        final Class<T> classType;
    
        public SoftCache(Class<T> typeParameterClass) {
            this.classType = typeParameterClass;
            mRecyclingStack = new Stack<Reference<T>>();
        }
    
        /* implement this to create new object of type T if cache is empty */
        public abstract T runWhenCacheEmpty();
    
        /*
         * retrieves last item from cache or creates a new T object if cache is
         * empty
         */
        public T get() {
            T itemCached = null;
    
            if (mRecyclingStack.isEmpty()) {
                itemCached = runWhenCacheEmpty();
    
            } else {
                SoftReference<T> softRef = (SoftReference<T>) mRecyclingStack
                        .pop();
    
                Object obj = softRef.get();
                /*
                 * if referent object is empty(due to GC) then create a new
                 * object
                 */
                if (obj == null) {
                    itemCached = runWhenCacheEmpty();
    
                }
                /*
                 * otherwise restore from cache by casting the referent as the
                 * class Type that was passed to constructor
                 */
                else {
                    itemCached = (classType.cast(softRef.get()));
                }
            }
            return itemCached;
        }
    
    现在方法实例化Item使用它的方式如下:

    @Override
        public Object instantiateItem(final ViewGroup container, final int position) {
           View MyPageView=myViewCache.get();
    
    }
    
    更新:如果您想对不同的版面使用缓存,或者不想扩展缓存,我提出了一个解决方案,您可以对多个版面使用相同的缓存,您可以使用版面ID检索放入的版面:

    public class SoftViewCache {
    
        private HashMap<Integer,ArrayList<SoftReference<View>>> multiMap;
    
        public SoftViewCache() {
            multiMap= new HashMap<Integer, ArrayList<SoftReference<View>>>();           
        }
    
        /*
         * retrieves cached item  or return null if cache is
         * empty
         */
        public View get(int id) {
            View itemCached = null;
            if (!multiMap.containsKey(id)) {
                return null;
            } 
            else {
                /*get the referent object and check if its already been GC if not we re-use*/
                SoftReference<View> softRef =multiMap.get(id).get(0);
                Object obj = softRef.get();
                /*
                 * if referent object is empty(due to GC) then caller must create a new
                 * object
                 */
                if (null == obj) {
                    return null;
                }
                /*
                 * otherwise restore from cache 
                 */
                else {
                    itemCached = (softRef.get());
                }
            }
            return itemCached;
        }
    
        /* saves a view object to the cache by reference, we use a multiMap to allow
         * duplicate IDs*/
        public void put(View item) {
            SoftReference<View> ref = new SoftReference<View>(item);
            int key = item.getId();
              /*check if we already have a reuseable layouts saved if so just add to the list
               * of reusable layouts*/
            if (multiMap.containsKey(key)) {
                multiMap.get(key).add(ref);
            } else {
                /*otherwise we have no reusable layouts lets create a list of reusable layouts
                 * and add it to the multiMap*/
                ArrayList<SoftReference<View>> list = new ArrayList<SoftReference<View>>();
                list.add(ref);
                multiMap.put(key, list);
            }
        }
    }
    
    公共类SoftViewCache{
    私有HashMap多重映射;
    公共SoftViewCache(){
    multiMap=新的HashMap();
    }
    /*
    *检索缓存项,如果缓存为空,则返回null
    *空的
    */
    公共视图获取(int-id){
    View itemCached=null;
    如果(!multiMap.containsKey(id)){
    返回null;
    } 
    否则{
    /*获取referent对象并检查它是否已经被GC使用,如果不是,我们将重新使用*/
    SoftReference softRef=multiMap.get(id).get(0);
    Object obj=softRef.get();
    /*
    *若引用对象为空(由于GC),则调用方必须创建一个新的
    *反对
    */
    if(null==obj){
    返回null;
    }
    /*
    *否则从缓存中恢复
    */
    否则{
    itemCached=(softRef.get());
    }
    }
    返回缓存项;
    }
    /*通过引用将视图对象保存到缓存中,我们使用多重映射来允许
    *重复ID*/
    公共作废放置(查看项目){
    软参考参考=新的软参考(项目);
    int key=item.getId();
    /*检查我们是否已经保存了一个可重用的布局,如果是,只需添加到列表中即可
    *可重用布局的设计*/
    if(多映射容器(键)){
    multiMap.get(key.add)(ref);
    }否则{
    /*否则,我们没有可重用的布局,让我们创建一个可重用布局列表
    *并将其添加到多重贴图中*/
    ArrayList=新建ArrayList();
    列表。添加(参考);
    multiMap.put(键、列表);
    }
    }
    }
    
    我通过定义一个
    RecycleCache
    解决了这个问题,如下所示

    protected static class RecycleCache {
    
      private final RecyclerPagerAdapter mAdapter;
    
      private final ViewGroup mParent;
    
      private final int mViewType;
    
      private List<ViewHolder> mCaches;
    
      public RecycleCache(RecyclerPagerAdapter adapter, ViewGroup parent, int viewType) {
        mAdapter = adapter;
        mParent = parent;
        mViewType = viewType;
        mCaches = new ArrayList<>();
      }
    
      public ViewHolder getFreeViewHolder() {
        int i = 0;
        ViewHolder viewHolder;
        for (int n = mCaches.size(); i < n; i++) {
          viewHolder = mCaches.get(i);
          if (!viewHolder.mIsAttached) {
            return viewHolder;
          }
        }
        viewHolder = mAdapter.onCreateViewHolder(mParent, mViewType);
        mCaches.add(viewHolder);
        return viewHolder;
      }
    }
    
    受保护的静态类RecycleCache{
    私人最终回收商Adapter mAdapter;
    私有最终视图组mParent;
    私有最终int mViewType;
    私人名单;
    公共RecycleCache(RecyclerPagerAdapter适配器、视图组父级、int-viewType){
    mAdapter=适配器;
    mParent=父母;
    mViewType=视图类型;
    mCaches=newarraylist();
    }
    公共视图持有者getFreeViewHolder(){
    int i=0;
    持票人持票人;
    对于(int n=mCaches.size();i

    在这里查看我的示例代码

    SoftViewCache.get(int id)替换SoftReference softRef=multiMap.get(id).get(0)中的一个小改动;使用softreferef=multiMap.remove(id).get(0);从缓存中删除,因为它不再可重用。这实际上是一个非常好的库。但它与这里的代码不同。怎么回事?检查这个解决方案对我有用很好的解决方案!
    @Override
        public Object instantiateItem(final ViewGroup container, final int position) {
           View MyPageView=myViewCache.get();
    
    }
    
    public class SoftViewCache {
    
        private HashMap<Integer,ArrayList<SoftReference<View>>> multiMap;
    
        public SoftViewCache() {
            multiMap= new HashMap<Integer, ArrayList<SoftReference<View>>>();           
        }
    
        /*
         * retrieves cached item  or return null if cache is
         * empty
         */
        public View get(int id) {
            View itemCached = null;
            if (!multiMap.containsKey(id)) {
                return null;
            } 
            else {
                /*get the referent object and check if its already been GC if not we re-use*/
                SoftReference<View> softRef =multiMap.get(id).get(0);
                Object obj = softRef.get();
                /*
                 * if referent object is empty(due to GC) then caller must create a new
                 * object
                 */
                if (null == obj) {
                    return null;
                }
                /*
                 * otherwise restore from cache 
                 */
                else {
                    itemCached = (softRef.get());
                }
            }
            return itemCached;
        }
    
        /* saves a view object to the cache by reference, we use a multiMap to allow
         * duplicate IDs*/
        public void put(View item) {
            SoftReference<View> ref = new SoftReference<View>(item);
            int key = item.getId();
              /*check if we already have a reuseable layouts saved if so just add to the list
               * of reusable layouts*/
            if (multiMap.containsKey(key)) {
                multiMap.get(key).add(ref);
            } else {
                /*otherwise we have no reusable layouts lets create a list of reusable layouts
                 * and add it to the multiMap*/
                ArrayList<SoftReference<View>> list = new ArrayList<SoftReference<View>>();
                list.add(ref);
                multiMap.put(key, list);
            }
        }
    }
    
    protected static class RecycleCache {
    
      private final RecyclerPagerAdapter mAdapter;
    
      private final ViewGroup mParent;
    
      private final int mViewType;
    
      private List<ViewHolder> mCaches;
    
      public RecycleCache(RecyclerPagerAdapter adapter, ViewGroup parent, int viewType) {
        mAdapter = adapter;
        mParent = parent;
        mViewType = viewType;
        mCaches = new ArrayList<>();
      }
    
      public ViewHolder getFreeViewHolder() {
        int i = 0;
        ViewHolder viewHolder;
        for (int n = mCaches.size(); i < n; i++) {
          viewHolder = mCaches.get(i);
          if (!viewHolder.mIsAttached) {
            return viewHolder;
          }
        }
        viewHolder = mAdapter.onCreateViewHolder(mParent, mViewType);
        mCaches.add(viewHolder);
        return viewHolder;
      }
    }