`
阿尔萨斯
  • 浏览: 4364109 次
社区版块
存档分类
最新评论

android 在UI线程之外处理Bitmap - 开发文档翻译

 
阅读更多

由于本人英文能力实在有限,不足之初敬请谅解

本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接


Processing Bitmaps Off the UI Thread

在UI线程之外处理Bitmap


The BitmapFactory.decode* methods, discussed in the Load Large Bitmaps Efficiently lesson, should not be executed on the main UI thread if the source data is read from disk or a network location (or really any source other than memory).

The time this data takes to load is unpredictable and depends on a variety of factors (speed of reading from disk or network, size of image, power of CPU, etc.).

If one of these tasks blocks the UI thread, the system flags your application as non-responsive and the user has the option of closing it (see Designing for Responsiveness for more information).

以BitmapFactory.decode*开头的方法已经在“Load Large Bitmaps Efficiently”中讨论过了,如果数据源在磁盘或者网络上,那么这些方法不应该在主UI线程中执行


This lesson walks you through processing bitmaps in a background thread using AsyncTask and shows you how to handle concurrency issues.

这里教你如何使用AsyncTask在后台线程中处理bitmap,并且展示如何处理并发问题


Use an AsyncTask

The AsyncTask class provides an easy way to execute some work in a background thread and publish the results back on the UI thread.

To use it, create a subclass and override the provided methods.

Here’s an example of loading a large image into an ImageView using AsyncTask and decodeSampledBitmapFromResource():

使用AsyncTask

AsyncTask类提供一种简单的方式来在后台线程执行一些工作并且把结果发布到UI线程上

为了使用它,建立一个子类,并且覆盖其中的方法

这有一个使用AsyncTask和decodeSampledBitmapFromResource()加载大图片到ImageView的例子

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private int data = 0;

    public BitmapWorkerTask(ImageView imageView) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        imageViewReference = new WeakReference<ImageView>(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.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

The WeakReference to the ImageView ensures that the AsyncTask does not prevent the ImageView and anything it references from being garbage collected.

There’s no guarantee the ImageView is still around when the task finishes, so you must also check the reference in onPostExecute().

The ImageView may no longer exist, if for example, the user navigates away from the activity or if a configuration change happens before the task finishes.

关联到ImageView上的WeakReference保证AsyncTask不会阻止ImageView和任何引用它的地方被垃圾回收

当task结束的时候,不保证ImageView仍然存在,所以你也必须在onPostExecute()中检查这个引用

假设例如:用户导航到activity之外或者如果在task结束之前一个配置改变的发生的时候,ImageView也许不复存在


To start loading the bitmap asynchronously, simply create a new task and execute it:

为了异步的加载bitmap,简单的建立一个新的task并且执行它

public void loadBitmap(int resId, ImageView imageView) {
    BitmapWorkerTask task = new BitmapWorkerTask(imageView);
    task.execute(resId);
}


Handle Concurrency

处理并发


Common view components such as ListView and GridView introduce another issue when used in conjunction with the AsyncTask as demonstrated in the previous section.

In order to be efficient with memory, these components recycle child views as the user scrolls.

If each child view triggers an AsyncTask, there is no guarantee that when it completes, the associated view has not already been recycled for use in another child view. Furthermore, there is no guarantee that the order in which asynchronous tasks are started is the order that they complete.

普通的view组件,例如当ListView 和 GridView与AsyncTask(像上一节展示的那样)一起使用的时候,会引入另外一个问题

为了在内存上的效率,当用户滚动屏幕的时候这些组件回收子view

如果每一个子view都触发一个AsyncTask,那么不保证当它完成的时候,关联的view为了在另一个子view中使用而没有被回收

而且,不保证异步任务开始的顺序与完成时的顺序一致


The blog post Multithreading for Performance further discusses dealing with concurrency, and offers a solution where the ImageView stores a reference to the most recent AsyncTask which can later be checked when the task completes.

Using a similar method, the AsyncTask from the previous section can be extended to follow a similar pattern.

这个blog发布了Multithreading for Performance,更深入的讨论并发的处理,并且提供了一个当任务完成后ImageView将一个引用存储到最近的一个并且之后能被检查的AsyncTask的解决方案

使用一个相似的方法,上一节提到的AsyncTask可以扩展为遵循一个相似的形式


Create a dedicated Drawable subclass to store a reference back to the worker task.

In this case, a BitmapDrawable is used so that a placeholder image can be displayed in the ImageView while the task completes:

建立一个专用的Drawable子类来存储一个关联到工作task的引用

这样,使用了BitmapDrawable,当task完成的时候一个站位的图片就能被显示到ImageView

static class AsyncDrawable extends BitmapDrawable {
    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

    public AsyncDrawable(Resources res, Bitmap bitmap,
            BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        bitmapWorkerTaskReference =
            new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
    }

    public BitmapWorkerTask getBitmapWorkerTask() {
        return bitmapWorkerTaskReference.get();
    }
}

Before executing the BitmapWorkerTask, you create an AsyncDrawable and bind it to the target ImageView:

在执行BitmapWorkerTask之前,你可以建立一个AsyncDrawable,并且把它绑定到目标ImageView上面

public void loadBitmap(int resId, ImageView imageView) {
    if (cancelPotentialWork(resId, imageView)) {
        final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
        final AsyncDrawable asyncDrawable =
                new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
        imageView.setImageDrawable(asyncDrawable);
        task.execute(resId);
    }
}

The cancelPotentialWork method referenced in the code sample above checks if another running task is already associated with the ImageView.

If so, it attempts to cancel the previous task by calling cancel().

In a small number of cases, the new task data matches the existing task and nothing further needs to happen.

Here is the implementation of cancelPotentialWork:

上面示例中的cancelPotentialWork方法检查是否另一个运行中的task已经关联到这个ImageView

如果是,它试图通过调用cancel()取消前一个任务

少数情况下,新的task数据与已存在的task匹配

下面是cancelPotentialWork的实现

public static boolean cancelPotentialWork(int data, ImageView imageView) {
    final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

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

A helper method, getBitmapWorkerTask(), is used above to retrieve the task associated with a particular ImageView:

上面使用的getBitmapWorkerTask()方法,用来获得与特定的ImageView关联的task

private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
   if (imageView != null) {
       final Drawable drawable = imageView.getDrawable();
       if (drawable instanceof AsyncDrawable) {
           final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
           return asyncDrawable.getBitmapWorkerTask();
       }
    }
    return null;
}

The last step is updating onPostExecute() in BitmapWorkerTask so that it checks if the task is cancelled and if the current task matches the one associated with the ImageView:

最后一步是在BitmapWorkerTask中更新onPostExecute(),以便检查这个task是否被取消、当前task是否与关联ImageView的task匹配

 class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    ...

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (isCancelled()) {
            bitmap = null;
        }

        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask =
                    getBitmapWorkerTask(imageView);
            if (this == bitmapWorkerTask && imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

This implementation is now suitable for use in ListView and GridView components as well as any other components that recycle their child views.

Simply call loadBitmap where you normally set an image to your ImageView.

For example, in a GridView implementation this would be in the getView() method of the backing adapter.

这种实现适用于ListView 和 GridView组件中,也适用于任何其他回收他们的子view的组件

在你通常给ImageView设置图片的地方简单的调用loadBitmap

例如,在一个GridView实现中,应该在其内部的adapter的getView()方法中调用loadBitmap


原文地址如下,英文水平实在有限,希望拍砖同时能给予指正。

http://developer.android.com/training/displaying-bitmaps/process-bitmap.html



转贴请保留以下链接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

分享到:
评论

相关推荐

    RoaringBitmap-0.7.45-API文档-中英对照版.zip

    包含翻译后的API文档:RoaringBitmap-0.7.45-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.roaringbitmap:RoaringBitmap:0.7.45; 标签:roaringbitmap、RoaringBitmap、中英对照文档、jar包、java...

    RoaringBitmap-0.5.11-API文档-中文版.zip

    包含翻译后的API文档:RoaringBitmap-0.5.11-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.roaringbitmap:RoaringBitmap:0.5.11; 标签:roaringbitmap、RoaringBitmap、jar包、java、中文文档; 使用方法:...

    RoaringBitmap-0.5.11-API文档-中英对照版.zip

    包含翻译后的API文档:RoaringBitmap-0.5.11-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:org.roaringbitmap:RoaringBitmap:0.5.11; 标签:roaringbitmap、RoaringBitmap、jar包、java、API文档、...

    RoaringBitmap-0.7.45-API文档-中文版.zip

    包含翻译后的API文档:RoaringBitmap-0.7.45-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.roaringbitmap:RoaringBitmap:0.7.45; 标签:roaringbitmap、RoaringBitmap、中文文档、jar包、java; 使用方法:...

    Android----线程实现图片移动

    线程在Android中扮演着处理后台任务的重要角色,它可以避免因为长时间运行操作而阻塞主线程,确保UI的流畅性。 首先,我们需要理解Android的线程模型。主线程,也被称为UI线程,负责处理所有的用户交互,如触摸事件...

    Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面

    ### Android异步处理详解:使用Thread+Handler实现非UI线程更新UI界面 #### 概述 Android系统中,每一个应用程序都运行在一个独立的Dalvik虚拟机进程中。当应用程序启动时,系统会创建一个主线程(MainThread),也...

    Android上解析24位深度Bitmap文件示例

    5. **异步加载**:为了防止UI线程阻塞,建议在后台线程中进行Bitmap的加载和解码。可以使用AsyncTask或者Android的Loader框架来实现。 6. **内存缓存**:Android提供LruCache或其他第三方库如Picasso或Glide,用于...

    android Bitmap特效处理

    在Android开发中,Bitmap是用于表示图像数据的基本类,它在UI设计和图像处理中扮演着重要角色。本文将深入探讨如何使用Bitmap实现各种特效处理,包括黑白特效、底片特效、浮雕特效、模糊特效、锐化特效以及怀旧特效...

    Android UI开发专题

    ### Android UI开发专题知识点概述 #### 一、Android UI开发概览 在移动应用开发领域,用户界面(User Interface, UI)设计对于提升用户体验至关重要。Android作为全球最广泛使用的移动操作系统之一,其UI开发能力...

    Android下利用Bitmap切割图片

    在Android开发中,Bitmap是处理图像的基本类,用于在内存中表示位图图像。当我们需要对图片进行裁剪、缩放或进行其他操作时,Bitmap提供了丰富的功能。本篇文章将详细探讨如何在Android环境下利用Bitmap来切割图片。...

    Android Bitmap 处理示例

    在Android开发中,Bitmap是用于表示图像数据的核心类,它在UI显示和图像处理中扮演着重要角色。然而,由于Bitmap对象通常占用大量的内存,不当的处理可能导致内存溢出(Out Of Memory)问题,因此对Bitmap进行高效...

    Android代码-Android-BitmapCache

    This project came about as part of my blog post: http://www.senab.co.uk/2012/07/01/android-bitmap-caching-revisited/ Android-BitmapCache is a specialised cache, for use with Android Bitmap objects. I...

    处理android bitmap oom

    4. **异步加载**:在UI线程之外加载Bitmap,如使用AsyncTask或Loader,防止因加载大图导致的ANR(Application Not Responding)问题。这也有助于提升用户体验,因为图片加载不会阻塞主线程。 5. **Bitmap Format...

    Android UI开发(五)Bitmap和Canvas实例.docx

    在Android UI开发中,Bitmap和Canvas是两个非常重要的概念,它们是实现自定义视图、图形绘制和图像处理的关键工具。Bitmap是Android中用于表示位图图像的数据结构,而Canvas则是一个画布,用于在屏幕上绘制这些位图...

    android中对Bitmap图片设置任意角为圆角

    在Android开发中,Bitmap是用于表示图像数据的基本对象,它是一种内存中的图片表示形式。而当我们需要在应用程序中展示带有圆角的图片时,通常会用到Bitmap的处理技巧。本篇文章将深入探讨如何在Android中对Bitmap...

    Android UI开发专题(五) Bitmap和Canvas实例

    在Android UI开发中,Bitmap和Canvas是两个非常重要的概念,它们是实现图形和图像处理的基础。Bitmap类代表了位图图像,而Canvas则用于在屏幕上画图,包括图像、文字和其他图形元素。在这个实例中,我们将深入理解...

    Android-使用Matrix对Bitmap进行处理

    在Android开发中,Bitmap是用于图像处理的基本对象,它存储并表示了图像的数据。而Matrix则是Android图形系统中的一个关键类,它允许我们对图像进行各种变换操作,如旋转、缩放、平移和倾斜等。这个教程将深入探讨...

    Android UI开发专题之界面设计

    2. **位图处理**:`android.graphics.Bitmap`类提供了丰富的位图处理功能,这对于优化UI设计具有重要意义。比如,可以使用`compress`方法将位图压缩成JPEG或PNG格式,便于在网络上传输;或者使用`createScaledBitmap...

    android studio上使用zxing-android-embedded实现二维码生成和扫描

    在Android开发中,ZXing(Zebra Crossing)是一个流行的条形码和二维码处理库,而zxing-android-embedded是ZXing库的一个简化版本,专为Android应用设计,方便集成到项目中实现二维码的生成和扫描功能。下面我们将...

    Android应用源码之(Bitmap位图渲染与操作).zip

    在Android应用开发中,Bitmap是用于处理图像的基本类,它代表了一个位图图像。位图渲染与操作是Android图形处理的重要部分,对于优化性能、创建动态效果和自定义UI至关重要。以下将详细讨论Bitmap的使用、渲染过程...

Global site tag (gtag.js) - Google Analytics