Android官方开发文档Training系列课程中文版:线程执行操作之线程间通讯
原文地址:http://android.xsoftlab.net/training/multiple-threads/communicate-ui.html
上節課我們學習了如何啟動一項由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 threadmHandler = new Handler(Looper.getMainLooper()) {...在Handler內,重寫handleMessage()方法。Android系統會在Handler所管理的線程中接收到一條新的消息時回調該方法:
/** handleMessage() defines the operations to perform when* the Handler receives a new Message to process.*/@Overridepublic 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 arraybyte[] imageBuffer = mPhotoTask.getByteBuffer();...// Runs the code for this taskpublic void run() {...// Tries to decode the image bufferreturnBitmap = BitmapFactory.decodeByteArray(imageBuffer,0,imageBuffer.length,bitmapOptions);...// Sets the ImageView BitmapmPhotoTask.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 poolssPhotoManager = 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 methodhandleState(outState);}...// Passes the state to PhotoManagervoid 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 taskspublic void handleState(PhotoTask photoTask, int state) {switch (state) {...// The task finished downloading and decoding the imagecase 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()) {@Overridepublic void handleMessage(Message inputMessage) {// Gets the task from the incoming Message object.PhotoTask photoTask = (PhotoTask) inputMessage.obj;// Gets the ImageView for this taskPhotoView localView = photoTask.getPhotoView();...switch (inputMessage.what) {...// The decoding is donecase 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官方开发文档Training系列课程中文版:线程执行操作之线程间通讯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cannot re-initialize
- 下一篇: Android官方开发文档Trainin