Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android官方開發文檔Training系列課程中文版:線程執行操作之線程間通訊

Android官方開發文檔Training系列課程中文版:線程執行操作之線程間通訊

編輯:關於Android編程

上節課我們學習了如何啟動一項由ThreadPoolExecutor所管理的線程任務。最後這節課我們將學習如何從任務中發送結果數據給UI線程。這項手段可以使任務在執行完畢後將結果顯示到UI中去。

每個APP擁有獨立的UI線程。只有在UI線程中創建的對象才可以訪問該線程中的其它對象。正因為運行任務的線程不是UI線程,所以它們不可以直接訪問UI對象。為了將數據從後台線程轉移到UI線程,需要使用運行在UI線程中的Handler對象。

在UI線程中定義Handler

Handler是Android系統框架管理線程的一部分。Handler對象專門用於接收消息處理消息。 一般來說,可以為新線程創建一個Handler,也可以為一個已經連接好的線程創建Handler。當你將Handler連接到UI線程時,處理消息的代碼都會運行在UI線程中。

在構建線程池的類的構造方法中實例化一個Handler對象,並將該對象的引用存儲於全局變量中。通過Handler(Looper)重載構造方法所實例化Handler可以與UI線程產生關聯。這個構造方法所使用的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內,重寫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;
            ...
        }
    ...
    }
}

將數據從非UI線程轉移到UI線程

為了將數據從後台進程轉移到UI進程,首先將數據的引用以及UI對象存儲於任務對象中。接下來,將該任務對象及狀態碼傳給由Handler對象所初始化的對象。在這個對象內,發送一條包含狀態碼的任務對象給Handler。因為Handler是運行在UI線程的,所以它可以將數據交給UI對象。

存儲數據於任務對象中

舉個例子,這裡有一個Runnable對象,運行於後台線程,它用於解碼一個Bitmap對象,並將其存儲於它所屬的對象PhotoTask中。該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還包含了一個用於展示Bitmap的ImageView的句柄。盡管引用Bitmap以及ImageView的是同一個對象,但是還是不能將Bitmap賦值給ImageView,因為當前並沒有處在UI線程中。

發送狀態到對象層級

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,然後通過這個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()中檢查每條消息的狀態。如果消息的狀態為TASK_COMPLETE,那麼表明該任務已經終結,那麼Message中所包含的PhotoTask對象包含了一個Bitmap以及一個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);
                    }
                    ...
                }
                ...
            }
            ...
    }
...
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved