使用Picasso加载图片的内存优化实践

jopen 9年前
   <h2>0 说明</h2>    <p>现在Android开源库中有许多图片加载框架,本文以picasso为例,总结下开发过程中的一些优化经验,使用的picasso版本如下</p>    <pre class="brush:java; toolbar: true; auto-links: false;">compile 'com.squareup.picasso:picasso:2.5.2'</pre>    <h2>1 图片裁剪</h2>    <p>在列表页尽量使用裁剪后的图片,在查看大图模式下才加载完整的图片。</p>    <p>图片裁剪示例</p>    <pre class="brush:java; toolbar: true; auto-links: false;">Picasso.with( imageView.getContext() ) .load(url) .resize(dp2px(250),dp2px(250)) .centerCrop() .into(imageView);</pre>    <p>picasso默认情况下会使用全局的ApplicationContext,即开发者传进去Activity,picasso也会通过activity获取ApplicationContext。</p>    <h2>2 查看大图放弃memory cache</h2>    <p>Picasso默认会使用设备的15%的内存作为内存图片缓存,且现有的api无法清空内存缓存。我们可以在查看大图时放弃使用内存缓存,图片从网络下载完成后会缓存到磁盘中,加载会从磁盘中加载,这样可以加速内存的回收。</p>    <pre class="brush:java; toolbar: true; auto-links: false;">Picasso.with(getApplication()) .load(mURL) .memoryPolicy(NO_CACHE, NO_STORE) .into(imageView);</pre>    <p>其中memoryPolicy的NO_CACHE是指图片加载时放弃在内存缓存中查找,NO_STORE是指图片加载完不缓存在内存中。</p>    <h2>3 RecyclableImageView</h2>    <p>重写ImageView的onDetachedFromWindow方法,在它从屏幕中消失时回调,去掉drawable引用,能加快内存的回收。</p>    <pre class="brush:java; toolbar: true; auto-links: false;">public class RecyclerImageView extends ImageView {      ...      @Override         protected void onDetachedFromWindow() {         super.onDetachedFromWindow();         setImageDrawable(null);        } }</pre>    <p>实验环境:加载大图不使用内存缓存。<br /> 实验场景:从图片列表页切换到详情页看大图,然后返回,不停重复。</p>    <div class="image-package" href="https://simg.open-open.com/show/f6abb8d0a76ec96b32a3053a0af0bd3b.jpg">    <img src="https://simg.open-open.com/show/f6abb8d0a76ec96b32a3053a0af0bd3b.jpg" width="700" height="261.23833757421545" data-original-src="https://simg.open-open.com/show/f6abb8d0a76ec96b32a3053a0af0bd3b.jpg" />     <br />     <div class="image-caption">     普通ImageView     </div>    </div>    <div class="image-package" href="https://simg.open-open.com/show/729eef81819220229c092eb12c6bcb8f.jpg">    <img src="https://simg.open-open.com/show/729eef81819220229c092eb12c6bcb8f.jpg" width="700" height="266.35030198446935" data-original-src="https://simg.open-open.com/show/729eef81819220229c092eb12c6bcb8f.jpg" />     <br />     <div class="image-caption">     RecyclableImageView     </div>    </div>    <p>可以看到使用了RecyclableImageView的实验在切换过程中产生的内存谷值明显优于ImageView,说明drawable更容易被回收。</p>    <h2>4 新进程中查看大图</h2>    <p>列表页的内存已经非常稳定,但是查看大图时,大图往往占用了20+m内存,加上现有进程中的内存,非常容易oom,在新进程中打开Activity成为比较取巧的避免oom的方式。</p>    <pre class="brush:java; toolbar: true; auto-links: false;"><activity android:name=".DetailActivity" android:process=":picture"/></pre>    <p>只要在AndroidManifest.xml中定义Activity时加入process属性,即可在新进程中打开此Activity。由此,picasso也将在新进程中创建基于新ApplicationContext的单例。</p>    <h2>5 列表页滑动优化</h2>    <p>picasso可以对多个加载请求设置相同的tag,即</p>    <pre class="brush:java; toolbar: true; auto-links: false;">Object tag = new Object();</pre>   <pre class="brush:java; toolbar: true; auto-links: false;">Picasso.with( imageView.getContext() ) .load(url) .resize(dp2px(250),dp2px(250)) .centerCrop() .tag(tag) .into(imageView);</pre>    <p>例如在RecyclerView滑动时监听,处理不同的表现:</p>    <pre class="brush:java; toolbar: true; auto-links: false;">mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){     @Override     public void onScrollStateChanged(RecyclerView recyclerView, int newState)     {         if (newState == RecyclerView.SCROLL_STATE_IDLE)         {             Picasso.with(context).resumeTag(tag);         }         else         {             Picasso.with(context).pauseTag(tag);         }     } });</pre>    <h2>6 RGB_565</h2>    <p>对于不透明的图片可以使用RGB_565来优化内存。</p>    <pre class="brush:java; toolbar: true; auto-links: false;">Picasso.with( imageView.getContext() ) .load(url) .config(Bitmap.Config.RGB_565) .into(imageView);</pre>    <p>默认情况下,Android使用ARGB_8888</p>    <pre class="brush:java; toolbar: true; auto-links: false;">Android中有四种,分别是: ALPHA_8:每个像素占用1byte内存 ARGB_4444:每个像素占用2byte内存 ARGB_8888:每个像素占用4byte内存 RGB_565:每个像素占用2byte内存</pre>    <p>RGB_565呈现结果与ARGB_8888接近,内存对比如下图</p>    <div class="image-package" href="https://simg.open-open.com/show/7af18ace4428fccfb87f953f6060e6b5.jpg">    <img src="https://simg.open-open.com/show/7af18ace4428fccfb87f953f6060e6b5.jpg" width="700" height="256.35451505016727" data-original-src="https://simg.open-open.com/show/7af18ace4428fccfb87f953f6060e6b5.jpg" />     <br />     <div class="image-caption">     默认ARGB_8888,列表滑动时平均内存10m     </div>    </div>    <div class="image-package" href="https://simg.open-open.com/show/f32669398be6c4c3a9b0af1b4b8fd12c.jpg">    <img src="https://simg.open-open.com/show/f32669398be6c4c3a9b0af1b4b8fd12c.jpg" width="700" height="263.6904761904762" data-original-src="https://simg.open-open.com/show/f32669398be6c4c3a9b0af1b4b8fd12c.jpg" />     <br />     <div class="image-caption">     RGB_565,列表滑动时,平均7M     </div>    </div>    <h2>7 reference</h2>    <p><a href="/misc/goto?guid=4959653369280416853" target="_blank">Picasso and Context</a><br /> <a href="/misc/goto?guid=4959653369375649094" target="_blank">JakeWharton的避免OOM建议</a><br /> <a href="/misc/goto?guid=4959653369453933124" target="_blank">Clear Cache memory of Picasso</a></p>    <p>来自: <a href="/misc/goto?guid=4959653369542032094" rel="nofollow" target="_blank">http://www.jianshu.com/p/6b746c904a49</a></p>