天天看点

Thinking in Google Doc-图片框架的实现及布局优化 用Hierarchyviewer,measure、layout、draw时间未显示? 

学习谷歌文档,总结如下:

1.图片加载框架的封装

    1)利用HttpURLConnection来封装网络加载图片的方法

    2)创建自定义的AsyncTask来封装1)中加载网络图片的方法,并显示到控件上。

    3)暴露方法封装2)中自定义的加载并显示图片的AsyncTask

    走完上面这几步,只需调用一个方法,就可以从网络上加载一张图片并且显示到控件上了。

  解决List并发下载图片错位的问题     

  但是,谷歌文档中说上面代码会存在一个问题。就是如果在List里使用,复用的话,可能会发生图

  图片错位的问题:就是某个item显示的图片,可能显示的图片是之前的item的图片。因为之前的这

  张图片可能加载时间比较长,滑动后imageview是复用的,所以后面的item可能会显示之前的item的

  图片。

  这种就是由于并发产生的问题,谷歌工程师是这么解决问题的:

  1》定义一个类 class DownloadedDrawable extends ColorDrawable,然后将下载的异步任务

    DownloadAsyncTask与其绑定起来。

<code>    </code><code>public</code> <code>static</code> <code>void</code>     <code>display(Context context,String url, ImageView imageView) {</code>

<code>        </code><code>Bitmap bitmapFromMemCache = LruCacheUtil.getBitmapFromMemCache(url);</code>

<code>        </code><code>if</code><code>(bitmapFromMemCache != </code><code>null</code><code>){</code>

<code>            </code><code>imageView.setImageBitmap(bitmapFromMemCache);</code>

<code>        </code><code>}</code><code>else</code><code>{</code>

<code>            </code><code>if</code> <code>(cancelPotentialDownload(url, imageView)) {</code>

<code>                </code><code>BitmapDownloaderTask task = </code><code>new</code> <code>BitmapDownloaderTask(context,imageView);</code>

<code>                </code><code>DownloadedDrawable downloadedDrawable = </code><code>new</code> <code>DownloadedDrawable(task);</code>

<code>                </code><code>imageView.setImageDrawable(downloadedDrawable);</code>

<code>                </code><code>task.execute(url);</code>

<code>            </code><code>}</code>

<code>        </code><code>}</code>

<code>    </code><code>}</code>

  2》定义2个方法 

    BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) 

     --得到与ImageView绑定的异步下载任务   

<code>    </code><code>public</code> <code>static</code>     <code>BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {</code>

<code>        </code><code>if</code> <code>(imageView != </code><code>null</code><code>) {</code>

<code>            </code><code>Drawable drawable = imageView.getDrawable();</code>

<code>            </code><code>if</code> <code>(drawable </code><code>instanceof</code> <code>DownloadedDrawable) {</code>

<code>                </code><code>DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;</code>

<code>                </code><code>return</code> <code>downloadedDrawable.getBitmapDownloaderTask();</code>

<code>        </code><code>return</code> <code>null</code><code>;</code>

    boolean cancelPotentialDownload(String url, ImageView imageView) 

    --取消可能正在进行的下载,并返回是否已经取消。   

      如果与imageView绑定的下载任务不为空,再判断与ImageView绑定的异步下载任务的URL,如果

   为null或者是与当前方法传递进来URL不一致,说明异步下载任务正在执行之前的下载,就取消任

   务,否则说明任务正在执行中且url一致,就不重新开启任务。  

<code>    </code><code>private</code> <code>static</code> <code>boolean</code>     <code>cancelPotentialDownload(String url, ImageView imageView) {</code>

<code>        </code><code>BitmapDownloaderTask bitmapDownloaderTask = BitmapDownloaderTask.getBitmapDownloaderTask(imageView);</code>

<code>    </code> 

<code>        </code><code>if</code> <code>(bitmapDownloaderTask != </code><code>null</code><code>) {</code>

<code>            </code><code>String bitmapUrl = bitmapDownloaderTask.url;</code>

<code>            </code><code>if</code> <code>((bitmapUrl == </code><code>null</code><code>) || (!bitmapUrl.equals(url))) {</code>

<code>                </code><code>bitmapDownloaderTask.cancel(</code><code>true</code><code>);</code>

<code>            </code><code>} </code><code>else</code> <code>{</code>

<code>                </code><code>// The same URL is already being downloaded.</code>

<code>                </code><code>return</code> <code>false</code><code>;</code>

<code>        </code><code>return</code> <code>true</code><code>;</code>

   解决图片缓存的问题  

    1》用内存来缓存,使用LruCache这个类。

     内存的特点:

       内存加载速度比较快,但是内存在开关机之后会被回收,缓存的数据会消失。

     底层:

      LinkedHashMap来实现存储    

     实现原理:

       当从url下载图片之前,先判断缓存中存不存在图片,如果存在直接加载图片,不存在则

      去网络请求图片。

       当AsyncTask下载完图片之后,如果不为null,就存放到缓存中。

      于是我写了个工具类LruCacheUtils来完成图片的缓存

<code>    </code><code>public</code> <code>class</code>     <code>LruCacheUtil {</code>

<code>        </code><code>//LruCache for bitmap</code>

<code>        </code><code>private</code> <code>static</code> <code>LruCache&lt;String, Bitmap&gt; mMemoryCache;</code>

<code>        </code><code>static</code> <code>{</code>

<code>            </code><code>// Get max available VM memory, exceeding this amount will throw an</code>

<code>            </code><code>// OutOfMemory exception. Stored in kilobytes as LruCache takes an</code>

<code>            </code><code>// int in its constructor.</code>

<code>            </code><code>final</code> <code>int</code> <code>maxMemory = (</code><code>int</code><code>) (Runtime.getRuntime().maxMemory() / </code><code>1024</code><code>);</code>

<code>            </code><code>// Use 1/8th of the available memory for this memory cache.</code>

<code>            </code><code>final</code> <code>int</code> <code>cacheSize = maxMemory / </code><code>8</code><code>;</code>

<code>            </code><code>mMemoryCache = </code><code>new</code> <code>LruCache&lt;String, Bitmap&gt;(cacheSize) {</code>

<code>                </code><code>@TargetApi</code><code>(Build.VERSION_CODES.HONEYCOMB_MR1)</code>

<code>                </code><code>@Override</code>

<code>                </code><code>protected</code> <code>int</code> <code>sizeOf(String key, Bitmap bitmap) {</code>

<code>                    </code><code>// The cache size will be measured in kilobytes rather than</code>

<code>                    </code><code>// number of items.</code>

<code>                    </code><code>return</code> <code>bitmap.getByteCount() / </code><code>1024</code><code>;</code>

<code>                </code><code>}</code>

<code>            </code><code>};</code>

<code>        </code><code>public</code> <code>static</code> <code>void</code> <code>addBitmapToMemoryCache(String key, Bitmap bitmap) {</code>

<code>            </code><code>if</code> <code>(getBitmapFromMemCache(key) == </code><code>null</code><code>) {</code>

<code>                </code><code>mMemoryCache.put(key, bitmap);</code>

<code>        </code><code>public</code> <code>static</code> <code>Bitmap getBitmapFromMemCache(String key) {</code>

<code>            </code><code>return</code> <code>mMemoryCache.get(key);</code>

   2》使用磁盘(Disk)来缓存,使用DiskLruCache(这个类google文档里并没有提供)

     Android DiskLruCache 源码解析 硬盘缓存的绝佳方案

    下载链接

    Android本地缓存DiskLruCache完整详细学习示例

    虽然利用内存来缓存,加载图片的时候速度比较快,但是像GridView会很快地占满内存。当应

     用非正常关闭(如被电话应用打断、运行在后台的时候被杀死)会导致cache被销毁清空。

     注意:获取图片应该在后台进行 

      Of course, fetching images from disk is slower than loading from memory and should be done in a       

                      background thread, as disk read times can be unpredictable.(from google doc)

     缓存位置:

       有外部存储设备就存放到外部存储设备中,否则存放到应用包名目录下。

2.布局优化

   sdk下的一些工具并不是专门针对Eclipse的,Android Studio也可以使用。  

   爽处1:可以查看布局结构某个节点的3个方法Measure、Layout、Draw执行所需要的时间,这样

        如果某个item的加载时间比较长,你就应该要优化了。

   使用这个工具可能会遇到的问题:

   问题:使用Hierarchyviewer,measure、layout、draw时间未显示?

   解决办法:点击菜单 Profile Node,重新加载之后就有了 

      本文转自屠夫章哥  51CTO博客,原文链接:http://blog.51cto.com/4259297/1710561,如需转载请自行联系原作者

继续阅读