欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-05-27 10:25:09
本节向你展示如何在任务中发送数据给ui线程里的对象,这个特性允许你在后台线程工作,完了在ui线程展示结果。 在ui线程定义一个handler handler是andro...

本节向你展示如何在任务中发送数据给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.