博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【后台任务】与UI线程通信(7)
阅读量:6374 次
发布时间:2019-06-23

本文共 5801 字,大约阅读时间需要 19 分钟。

概要


前面的教程指导您如何在线程池线程上运行代码,向您展示如何在由其管理的线程上启动任务 ThreadPoolExecutor。本最后一课向您展示了如何将数据从任务发送到在用户界面(UI)线程上运行的对象。此功能允许您的任务执行后台工作,然后将结果移至UI元素(如位图)。

每个应用程序都有自己的特殊线程来运行诸如对象之类的UI View 对象; 这个线程被称为UI线程。只有在UI线程上运行的对象才能访问该线程上的其他对象。因为您在线程池中的线程上运行的任务 未在UI线程上运行,所以他们无法访问UI对象。要将数据从后台线程移动到UI线程,请使用在UI线程Handler上运行的数据。

在UI线程上定义一个处理程序


Handler是Android系统管理线程框架的一部分。甲 Handler对象接收消息并运行的代码来处理消息。通常,您Handler为一个新线程创建一个线程,但您也可以创建一个Handler与现有线程连接的线程。当你连接Handler到你的UI线程时,处理消息的代码在UI线程上运行。

Handler在创建线程池的类的构造函数中 实例化对象,并将该对象存储在全局变量中。通过使用Handler(Looper) 构造函数实例化它,将它连接到UI线程。这个构造函数使用一个Looper对象,这是Android系统线程管理框架的另一部分。当你Handler基于一个特定的Looper实例来实例化一个 实例的时候, Handler它就像在同一个线程上运行Looper。例如

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

在里面Handler,覆盖handleMessage()方法。当Android系统收到它正在管理的线程的新消息时调用此方法; 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;            ...        }    ...    }}

下一节将介绍如何告诉Handler移动数据。

将数据从任务移至UI线程


要将数据从后台线程上运行的任务对象移动到UI线程上的对象,请首先将对数据和UI对象的引用存储在任务对象中。接下来,将任务对象和状态码传递给实例化该对象的对象Handler。在这个对象中,发送一个Message包含状态和任务对象给Handler。由于Handler正在UI线程上运行,因此它可以将数据移动到UI对象。

将数据存储在任务对象中

例如,下面是一个Runnable在后台线程上运行的×××Bitmap,它将其解码 并存储在其父对象中PhotoTask。该Runnable还存储状态代码DECODE_STATE_COMPLETED。

// A class that decodes photo files into Bitmapsclass 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在同一个对象,你不能分配Bitmap到ImageView,因为你目前没有在UI线程上运行。

相反,下一步是将此状态发送给PhotoTask对象。

向对象层次发送状态

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

将数据移动到用户界面

从PhotoTask对象中,PhotoManager对象接收状态码和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,则任务完成,并且该PhotoTask对象Message包含a Bitmap和an ImageView。由于 Handler.handleMessage()正在UI线程上运行,因此可以安全地将其Bitmap移至 ImageView:

private PhotoManager() {        ...            mHandler = new Handler(Looper.getMainLooper()) {                @Override                public void handleMessage(Message inputMessage) {                    // Gets the task from the incoming Message object.                    PhotoTask photoTask = (PhotoTask) inputMessage.obj;                    // Gets the ImageView for this task                    PhotoView localView = photoTask.getPhotoView();                    ...                    switch (inputMessage.what) {                        ...                        // The decoding is done                        case TASK_COMPLETE:                            /*                             * Moves the Bitmap from the task                             * to the View                             */                            localView.setImageBitmap(photoTask.getImage());                            break;                        ...                        default:                            /*                             * Pass along other messages from the UI                             */                            super.handleMessage(inputMessage);                    }                    ...                }                ...            }            ...    }...}

更多信息


要了解更多关于Android上的多线程操作的信息,请参阅指南。

示例应用


要尝试本指南中的概念,请下载。

Lastest Update:2018.04.17

联系我

QQ:94297366

微信打赏:

公众号推荐:

【后台任务】与UI线程通信(7)

转载于:https://blog.51cto.com/4789781/2124451

你可能感兴趣的文章
地图点聚合优化方案
查看>>
Google Chrome 快捷方式
查看>>
备考PMP心得体会
查看>>
vue proxy匹配规则
查看>>
线上应用故障排查之一:高CPU占用
查看>>
Extend Volume 操作 - 每天5分钟玩转 OpenStack(56)
查看>>
IronPython教程
查看>>
squid via检测转发循环
查看>>
计算分页
查看>>
iptables 做nat路由器脚本
查看>>
数据结构(C语言版)第三章:栈和队列
查看>>
Stopping and/or Restarting an embedded Jetty in...
查看>>
Oracle存储过程中的数据集输入参数
查看>>
vsftp 配置
查看>>
VCSA中配置时间和时区,实测至6.5适用
查看>>
高并发IM系统架构优化实践
查看>>
产品经理教你玩转阿里云负载均衡SLB系列(一):快速入门--什么是负载均衡
查看>>
有关linux--进程组、会话、守护进程详解
查看>>
我的友情链接
查看>>
monkeyrunner运行Python脚本来检查apk渠道和验证是否可以调用微信
查看>>