ǰλã >> Android >> Android进阶l习 - 高效昄BitͼQ在UIȝE?处理BitͼQ?
  ϸ

Android进阶l习 - 高效昄BitͼQ在UIȝE?处理BitͼQ?

ȶȣ254   ʱ䣺2016-05-01 11:03:38.0
Android进阶l习 - 高效昄BitmapQ在UIȝE?处理BitmapQ?

在UIȝE?处理Bitmap

     BitmapFactory.decode*  pd的方法,讨?的是怎么样去高效的加载大囄Q但?图片数?来源Q这些方法都不应该在UIȝE上使用。因些方法?费的旉???估的Q图片加载?费的旉依赖于很多的因素Q网l或?的?写?度,囄的大,手机CPU的?理能力等{)。在E序???其中?囄加蝲dd?了UIȝE,那么你的应用会无响应(ANRQ不能再与用戯行交互了Q,Androidpȝ会显C?知用P用户会选择关闭你的应用Q这?w怸好的用户体验?/div>

     Z这?原因Q你?使用  AsyncTask 来在UIȝE?的线E中处理囄加蝲Q但还有???Q?妥善处理好并发的??Q下面将介绍这两U问题的处理Ҏ

使用AsyncTask

       AsyncTask cMؓ我们提供了一U很好的方式来在UIȝE之外的U程?行一些任务,q且把任务的l果返回到UIȝE上。你??l承AsyncTask cd重蝲?提供的方法来使用这?异?d方式Q下面是?CZE序 
class BitmapWorkerTask extends AsyncTask {    private final WeakReference imageViewReference;    private int data = 0;    public BitmapWorkerTask(ImageView imageView) {        // Use a WeakReference to ensure the ImageView can be garbage collected        imageViewReference = new WeakReference(imageView);    }    // Decode image in background.    @Override    protected Bitmap doInBackground(Integer... params) {        data = params[0];        return decodeSampledBitmapFromResource(getResources(), data, 100, 100));    }    // Once complete, see if ImageView is still around and set bitmap.    // 此方法运行在UIȝE上    @Override    protected void onPostExecute(Bitmap bitmap) {        if (imageViewReference != null && bitmap != null) {            final ImageView imageView = imageViewReference.get();            if (imageView != null) {                imageView.setImageBitmap(bitmap);            }        }    }}

使用弱引用去保存 ImageView 对象?ؓ了确?/span> AsyncTask 不会d\?/span>ImageView 的用和垃圾回收器能够回?/span>ImageView 引用的?象?不能保证当任务完成的时?ImageView 引用的?象没有?回收Q所以呢你必donPostExecute() Ҏ?行?查是否ؓnull?/span>ImageView 对象?会不存在了,例?Q在?dl束前,用户?已经d了当前的用户界面QActivity被destroyQ或者一?|?Q例如横f屏切换Q发生改? Q所以在使用的时候必d?ImageView 对象做必要的??  

     你可以直接创Z?/span>AsyncTask 对象q调用execute()Ҏ来异步加载图?/span>
public void loadBitmap(int resId, ImageView imageView) {    BitmapWorkerTask task = new BitmapWorkerTask(imageView);    task.execute(resId);}

处理q发??

      ?a href="http://www.android-doc.com/reference/android/widget/ListView.html" style="font-family:'courier new',courier,monospace; font-weight:bold; line-height:21px; color:rgb(37,138,175); text-decoration:initial">ListView?a href="http://www.android-doc.com/reference/android/widget/GridView.html" style="font-family:'courier new',courier,monospace; font-size:14px; font-weight:bold; line-height:21px; color:rgb(37,138,175); text-decoration:initial">GridView 这?常?的?囄Ӟl合AsyncTask ?v使用的时候会产生另????。ؓ了尽?的提高内存的使用效率Q当用户滚动lgӞ这类视图lg会@?用它的子视图Q?果每?视图都姦发一?span style="background-color:rgb(249,249,249); color:rgb(34,34,34); font-family:Roboto,sans-serif; font-size:14px; line-height:19px"> AsyncTask Q那么将不会有保证相兌的?图是否已l回收供另??子?囑@?用了。?且,异?d的执行顺序并不意味着d的执行结束时的顺序也?L。结合这两?原因Q引发的这个q发??有可能会D囄讄雭视图上时会发生错位?

      针?这?q发、错位问题,我们??a href="http://www.android-doc.com/reference/android/widget/ImageView.html" style="font-family:'courier new',courier,monospace; font-size:14px; font-weight:bold; line-height:21px; background-color:rgb(249,249,249); color:rgb(37,138,175); text-decoration:initial">ImageView 对象存储??使用?a href="http://www.android-doc.com/reference/android/os/AsyncTask.html" style="font-family:'courier new',courier,monospace; font-size:14px; font-weight:bold; line-height:21px; color:rgb(37,138,175); text-decoration:initial">AsyncTask 的引?这样我们?L?任务是否完?/div>

     创徏?专用?a href="http://www.android-doc.com/reference/android/graphics/drawable/Drawable.html" style="font-family:'courier new',courier,monospace; font-size:14px; font-weight:bold; line-height:21px; color:rgb(37,138,175); text-decoration:initial">Drawable 子类来存储一?之?应的AsyncTask (这个AsyncTask 实际上是用来加蝲Drawable 的任?Q当囄加蝲d还在执?Ӟ可以用这?a href="http://www.android-doc.com/reference/android/graphics/drawable/Drawable.html" style="font-family:'courier new',courier,monospace; font-size:14px; font-weight:bold; line-height:21px; color:rgb(37,138,175); text-decoration:initial">Drawable 来显CZ张默认的囄了,当任务完成时这个Drawable随之??/div>

//存储??之?应的taskQ?在任务还在执行时充当?占位W,当任务完成时Q随之?替换static class AsyncDrawable extends BitmapDrawable {    private final WeakReference bitmapWorkerTaskReference;    public AsyncDrawable(Resources res, Bitmap bitmap,            BitmapWorkerTask bitmapWorkerTask) {        super(res, bitmap);        bitmapWorkerTaskReference =            new WeakReference(bitmapWorkerTask);    }    public BitmapWorkerTask getBitmapWorkerTask() {        return bitmapWorkerTaskReference.get();    }}

    在执行任务之前,先?|?位?Q?/span>ImageView 显C默认图?/span>
public void loadBitmap(int resId, ImageView imageView) {    if (cancelPotentialWork(resId, imageView)) {        final BitmapWorkerTask task = new BitmapWorkerTask(imageView);        // mPlaceHolderBitmap 引用的就?认?昄的图片??        final AsyncDrawable asyncDrawable =                new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);        imageView.setImageDrawable(asyncDrawable);        task.execute(resId);    }}

   cancelPotentialWork Ҏ?来?与ImageView 相关联的另??d?正在执?Q?果是的话Q将会?过调?/span>cancel()Ҏ?/span>关闭这个 d。只有极部分的情况下两?务的囄数据会相{,如果相等的话Q那也不会出C么并发问题了Q我?不需要做M的??/span>
public static boolean cancelPotentialWork(int data, ImageView imageView) {    // 取得当前与ImageView相关联的d    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);         // 如果存在的话Q则取消    if (bitmapWorkerTask != null) {        final int bitmapData = bitmapWorkerTask.data;        if (bitmapData != data) {            // Cancel previous task            bitmapWorkerTask.cancel(true);        } else {            // The same work is already in progress            return false;        }    }    // No task associated with the ImageView, or an existing task was cancelled    return true;}

   下面?/span>getBitmapWorkerTask() Ҏ的定?/span>
private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {   // imageView有可能?回收   if (imageView != null) {       final Drawable drawable = imageView.getDrawable();       if (drawable instanceof AsyncDrawable) {           final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;           return asyncDrawable.getBitmapWorkerTask();       }    }    return null;}     

     雜?/span> onPostExecute() Ҏ?????d??消了Q还有需要?下当前的任务是否是与imageView相关联的d 
class BitmapWorkerTask extends AsyncTask {    ...    @Override    protected void onPostExecute(Bitmap bitmap) {        // if task cancelled , this method is never invoked        // why check here ?         if (isCancelled()) {            bitmap = null;        }        if (imageViewReference != null && bitmap != null) {            final ImageView imageView = imageViewReference.get();            final BitmapWorkerTask bitmapWorkerTask =                    getBitmapWorkerTask(imageView);            // 判断当前task??兌的task            if (this == bitmapWorkerTask && imageView != null) {                imageView.setImageBitmap(bitmap);            }        }    }}

     前面的ImageView加蝲的实现方式?用于?/span> ListView and GridView 这类的UI视图lgQ我?以在Adapter?getView()  Ҏ??/span>loadBitmap Ҏ