Android后台线程和UI线程通讯实例

作者:冰冻鱼 时间:2023-04-20 23:01:19 

本节向你展示如何在任务中发送数据给UI线程里的对象,这个特性允许你在后台线程工作,完了在UI线程展示结果。

在UI线程定义一个Handler

Handler是Android系统线程管理框架里的一部分。一个Handler对象接收消息,并且运行代码来处理消息。正常情况下,你为新线程创建Handler,但你也可以为已有的线程创建一个Handler.当你连接Handler到UI线程时,处理消息的代码会在UI线程上运行.

在创建线程池的类的构造器里实例化Handler对象,保存在全局变量里。用Handler(Looper)方法实例化,连接到UI线程,构造方法使用Looper对象,也是Android系统线程管理框架里的一部分.Looper类有一个静态方法getMainLooper()可以获取UI线程的Looper对象。如:


private PhotoManager() {
...
    // Defines a Handler object that's attached to the UI thread
    mHandler = new Handler(Looper.getMainLooper()) {
    ...

在Handler里,覆盖handleMessage()。Android系统会在Handler管理的线程收到新消息时,调用该方法。一个指定线程的所有Handler对象都会收到相同的消息。

        /*
         * handleMessage() defines the operations to perform when
         * the Handler receives a new Message to process.
         */
        @Override
        public void handleMessage(Message inputMessage) {
            // Gets the image task from the incoming Message object.
            PhotoTask photoTask = (PhotoTask) inputMessage.obj;
            ...
        }
    ...
    }
}

从任务里移动数据到UI线程

要从后台线程的任务里移动数据到UI线程的对象,先保存引用到数据和任务对象的UI对象里,接下来把任务对象和状态码传给Handler对象。在这个对象里,发送一个包含状态 和任务对象的消息给Handler.因为Handler在UI线程上运行,它可以移动数据给UI对象。

在任务对象里存储数据

如,这是一个Runnable,运行在后台线程,它解析Bitmap,并保存到它的父对象。Runnable同时保存状态码DECODE_STATE_COMPLETED。


// A class that decodes photo files into Bitmaps
class PhotoDecodeRunnable implements Runnable {
    ...
    PhotoDecodeRunnable(PhotoTask downloadTask) {
        mPhotoTask = downloadTask;
    }
    ...
    // Gets the downloaded byte array
    byte[] imageBuffer = mPhotoTask.getByteBuffer();
    ...
    // Runs the code for this task
    public void run() {
        ...
        // Tries to decode the image buffer
        returnBitmap = BitmapFactory.decodeByteArray(
                imageBuffer,
                0,
                imageBuffer.length,
                bitmapOptions
        );
        ...
        // Sets the ImageView Bitmap
        mPhotoTask.setImage(returnBitmap);
        // Reports a status of "completed"
        mPhotoTask.handleDecodeState(DECODE_STATE_COMPLETED);
        ...
    }
    ...
}
...

PhotoTask还包含一个ImageView引用,用来显示Bitmap.尽管引用Bitmap和ImageView是在同一个对象里,但因为不是在UI线程,你不能直接让ImageView显示Bitmap.

沿对象层次逐级发送状态

PhotoTask持有解码的数据和显示数据的View对象的引用,它从PhotoDecodeRunnable接收到状态码,并且沿着线程池里引用的对象和Handler实例传送。


public class PhotoTask {
    ...
    // Gets a handle to the object that creates the thread pools
    sPhotoManager = PhotoManager.getInstance();
    ...
    public void handleDecodeState(int state) {
        int outState;
        // Converts the decode state to the overall state.
        switch(state) {
            case PhotoDecodeRunnable.DECODE_STATE_COMPLETED:
                outState = PhotoManager.TASK_COMPLETE;
                break;
            ...
        }
        ...
        // Calls the generalized state method
        handleState(outState);
    }
    ...
    // Passes the state to PhotoManager
    void handleState(int state) {
        /*
         * Passes a handle to this task and the
         * current state to the class that created
         * the thread pools
         */
        sPhotoManager.handleState(this, state);
    }
    ...
}

移动数据到UI

PhotoManager从PhotoTask对象接收到状态码和PhotoTask对象的句柄。因为状态是TASK_COMPLETE,创建一个包含状态和任务对象的Message,发送给Handler。


public class PhotoManager {
    ...
    // Handle status messages from tasks
    public void handleState(PhotoTask photoTask, int state) {
        switch (state) {
            ...
            // The task finished downloading and decoding the image
            case TASK_COMPLETE:
                /*
                 * Creates a message for the Handler
                 * with the state and the task object
                 */
                Message completeMessage =
                        mHandler.obtainMessage(state, photoTask);
                completeMessage.sendToTarget();
                break;
            ...
        }
        ...
    }

最终,Handler.handleMessage()为每个进来的Message检查状态码。如果状态码是TASK_COMPLETE,任务就是完成了,Message里的PhotoTask对象包含Bitmap和ImageView.因为Handler.handleMessage()运行在UI线程,它可以安全地为ImageView设置Bitmap.

标签:Android,后台线程,UI线程
0
投稿

猜你喜欢

  • Java实现并查集示例详解

    2023-07-17 05:41:34
  • 浅谈Android开发中项目的文件结构及规范化部署建议

    2022-05-13 12:47:37
  • Android中把bitmap存成BMP格式图片的方法

    2022-10-02 10:09:16
  • android SDk中常用的java包介绍

    2021-12-18 01:04:45
  • Java获取中文拼音、中文首字母缩写和中文首字母的示例

    2021-07-18 14:28:16
  • 简单讲解java中throws与throw的区别

    2022-06-01 05:16:55
  • Java 并发编程之线程挂起、恢复与终止

    2022-02-18 11:51:51
  • Java分布式学习之Kafka消息队列

    2022-04-10 22:22:47
  • 详解Java 信号量Semaphore

    2021-12-22 11:10:36
  • Java数据结构之队列(动力节点Java学院整理)

    2021-09-22 04:58:19
  • Android键盘输入语言设置默认打开myanmar缅甸语的步骤

    2021-07-01 17:15:44
  • 基于java构造方法Vector创建对象源码分析

    2023-11-25 11:27:54
  • Android实现简单的照相功能

    2023-07-01 08:46:16
  • Android自定义WaveProgressView实现水波纹加载需求

    2021-07-29 02:06:00
  • C++ 继承,虚继承(内存结构)详解

    2023-09-05 21:28:01
  • java原生序列化和Kryo序列化性能实例对比分析

    2023-11-26 16:04:20
  • WPF Slider滑动条的颜色修改方法

    2022-06-15 20:49:38
  • Java中equalsIgnoreCase()方法的使用

    2022-07-28 15:13:45
  • C#开发中的垃圾回收机制简析

    2022-08-06 14:10:56
  • SpringBoot2整合Redis实现读写操作

    2023-08-03 08:19:24
  • asp之家 软件编程 m.aspxhome.com