首页 > 代码库 > Hander

Hander

多线程与UI线程间通信

向你展示如何从任务发送数据对象上运行用户界面(UI)线程。该特性允许你的任务做背景的工作结果,然后再到UI元素如位图。

       每个应用程序都有自己的特殊的线程运行的UI对象如视图对象; 这个线程称为UI线程。只有在UI线程上运行对象访问其他线程的对象。因为你的任务运行在一个线程从一个线程池不是UI线程上运行,他们没有对UI对象的访问。将数据从一个后台线程到UI线程,使用Handler的UI线程上运行。

在UI线程上定义一个Handler

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

 

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

Looper一样运行在相同的线程

代码例子:

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

里面的Handler,重写了handlerMessage()方法。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;
            ...
        }...}
}
The next section shows how to tell the Handler to move data.

后台线程与UI线程交换数据

运行在后台的线程任务与UI线程交换数据,首先引用数据和UI对象存储在任务对象。接下来,通过任务对象和一个状态码来实例化的对象处理程序。在这个对象,包含状态和任务对象发送一个消息Handler。因为Handler是在UI线程上运行,它可以将数据移动到UI对象。.

 

在任务对象存储数据

例如, 这里有一个 Runnable, 运行在一个后台线程, 解码一个PhotoTask位图并将其存储在它的父对象。The 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也包含一个处理ImagVie显示位图。尽管引用同一个对象的bitmap和ImageView,, 你不能分配ImageView的位图, 因为你不是目前在UI线程上运行。

相反,下一步是把这状态发送到PhotoTask对象。

发送状态的对象层次结构

PhotoTask 在层次结构中是下一个更高的对象。它维护引用的解码数据和视图对象将显示数据。它从PhotoDecodeRunnable接收状态代码,并将它传递到维护线程池和实例化的对象处理程序:

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

从PhotoTask对象,PhotoManager对象接收状态代码和PhotoTask对象的句柄。因为状态TASK_COMPLETE,创建一个消息包含状态和任务对象并将它发送到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()检查每个传入消息的状态码。如果TASK_COMPLETE状态代码,然后,任务完成后,PhotoTask对象在消息中包含一个位图和一个ImageView。因为Handler.handleMessage()在UI线程上运行,它可以安全地移动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);
                    }
                    ...
                }
                ...
            }
            ...
    }
...
}