29

我有一個尋呼機適配器,假設膨脹一個複雜的視圖表示日曆。如何實現PagerAdapter的查看回收機制?

大約需要大約350毫秒來誇大日曆的每年。

爲了提高性能,我希望實現ListView陣列回收視圖(convertView參數getView())中存在的機制。

這是我目前的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; 
} 

任何指針或方向來實現這樣的行爲? 特別是在適配器中,我怎麼能知道DateTileGridViews中的一個正在被刷屏,所以我可以將它保存在內存中以便下次重新使用它。

回答

31

所以我想通了。

  1. 覆蓋destroyItem(ViewGroup container, int position, Object view) ANS節省您的緩存的視圖
  2. 創建一個單獨的方法,看看是否有任何機會使用回收的觀點還是應該誇大一個新的。
  3. 記得從緩存中刪除回收的視圖,一旦它被使用,以避免有相同的視圖附加到尋呼機相同的看法。

這裏是代碼。我使用的視圖堆棧緩存從我的傳呼機全部拆除意見

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()); 
} 

不要忘記實例化堆棧在適配器構造函數。

+0

非常感謝您! – penguin86

3

我是這樣做的..首先創建抽象softCache類:如果你希望它是一個視圖類

public class ViewCache extends SoftCache<View>{ 

      public ViewCache(Class<View> typeParameterClass) { 
       super(typeParameterClass); 
      } 

      @Override 
      public View runWhenCacheEmpty() { 
       return mFragment.getActivity().getLayoutInflater() 
         .inflate(R.layout.mypagelayout, null); 
      } 
     } 

然後在構造函數實例化這樣的:

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; 
    } 

現在從SoftCache繼承,所以我們可以實現runWhenCacheEmpty方法

SoftCache<View> myViewCache = new ViewCache(View.class); 
現在

在destroyItem視圖保存到緩存::例如(但它可以用於任何類型的類工作)

@Override 
    public void destroyItem(final ViewGroup container, final int position, final Object object) { 
     final View v = (View) object; 

     if(v.getId() == R.id.mypagelayout) 
      myViewCache.put(v); //this saves it 


    } 

現在方法instantiateItem利用它只是這樣的:

@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); 
     } 
    } 
} 
+0

SoftViewCache.get(int id)中的一個小改動替換爲SoftReference softRef = multiMap.get(id).get(0);與SoftReference softRef = multiMap.remove(id).get(0);從緩存中刪除,因爲它不再可用於重用。 –

2

我解決了這個定義一個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; 
    } 
} 

這裏看看我的示例代碼RecyclerPagerAdapter

+0

完美,謝謝! – georgehardcore

+0

這實際上是一個非常好的圖書館。但它與這裏的代碼不一樣。怎麼來的? –

+0

在這裏發佈後,代碼有了一些改進。 –