Fresco源码分析-SimpleDraweeView在ListView里怎么释放内存的?

       ListView的Item有图片, 当条数很多例如超过1000条,如果不做任何处理,  划动ListView会出现OOM导致应用崩溃。  我们现在都用了三方开源图库框架, 并没有出现OOM,   从而可能忽视了其实现原理,  现在是时候回顾一下了。

       先回顾一下ListView的基本知识, ListView继承于AbsListView,  AbsListView有个内部类RecycleBin用于复用view,BaseAdpater里getView方法中convertView参数就是从RecycleBin类对象缓存中取的。

注释:The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the start of a layout. By construction, they are displaying current information. At the end of layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that could potentially be used by the adapter to avoid allocating views unnecessarily.

        如果ListView中Item用的是ImageView, 要释放它显示的bitmap, 就要删除对bitmap的引用! 引用计数为0时, Bitmap才会被GC回收。 问题是在哪里取消引用? ListView提供了回调。

        有2种办法释放ListView中Item的图片资源, 即删除对bitmap的引用。

第1种方法:  使用ImageView显示图片后, Bitmap的引用计数为1, 在Item移出屏幕时会删除该子View并添加到RecycleBin中, 在这个过程里RecycleBin执行了回调函数。

AbsListView.java源码:

void addScrapView(View scrap, int position) {
    ...
    if (mRecyclerListener != null) {
         mRecyclerListener.onMovedToScrapHeap(scrap);
     }
}
        我们只要设置回调函数就可以, 如下参考代码:

        listView.setRecyclerListener(new AbsListView.RecyclerListener() {
            @Override
            public void onMovedToScrapHeap(View view) {  //这个view就是BaseAdapter类getView函数的convertView
                ViewHolder holder = (ViewHolder) view.getTag();
                holder.mImageView.setImageDrawable(null);  //bitmap就是被ImageView的mDrawable引用了
            }
        });
          设置ImageView为空或占位图,  占位图可以是shape, 因为它很小 。   这样ImageView原来显示的bitmap引用计数为0, GC会自动回收了。   


第2种方法: View在被ListView移出屏幕时会执行onDetach函数, 哈哈!   想必你应该知道怎么办了吧,    新建个自定义View,继承ImageView并覆盖onDetach函数, 在onDetach函数里释放引用就行了。 Fresco就是这么干的, 看源码,  在xml布局文件里是SimpleDraweeView, 而不是ImageView。

  
          SimpleDraweeView继承于GenericDraweeView, GenericDraweeView继承于DraweeView。   注意DraweeView覆盖了onDetach函数!!! 并在onDetach函数里释放资源。这就是为什么fresco用在ListView中不会OOM的原因。
Fresco源码分析-SimpleDraweeView在ListView里怎么释放内存的?_第1张图片

  /**
   * Does the actual work of detaching.
   *
   * Non-test subclasses should NOT override. Use onDetach for custom code.
   */
  protected void doDetach() {
    mDraweeHolder.onDetach();
  }

        上面说的还不够详细,  建议下载fresco源码写些测试代码验证加深理解



你可能感兴趣的:(Java)