編輯:關於Android編程
上節課我們學習了如何啟動一項由ThreadPoolExecutor所管理的線程任務。最後這節課我們將學習如何從任務中發送結果數據給UI線程。這項手段可以使任務在執行完畢後將結果顯示到UI中去。
每個APP擁有獨立的UI線程。只有在UI線程中創建的對象才可以訪問該線程中的其它對象。正因為運行任務的線程不是UI線程,所以它們不可以直接訪問UI對象。為了將數據從後台線程轉移到UI線程,需要使用運行在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對象存儲於任務對象中。接下來,將該任務對象及狀態碼傳給由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); } ... }
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.一些BB上節我們把妹子圖片的數據來源從本地改成了解析Gank提供的接口數據,我們本節想對這個圖片加載類進行優化,比如加上顯示本地圖片的,另外還有一點就是緩存,我們現在
對Android 利用ViewPager實現圖片可以左右循環滑動效果,感興趣的朋友可以直接點擊查看內容詳情。主要介紹如何實現ViewPager自動播放,循環滾動的效果及使
由於Android幾乎所有的代碼都是公開的,如果要對Framework層分析就必需先拿到Framework層的代碼,我在前面已經搭建好了ubuntu14.04的環境,下載
問題 在Android中使用內嵌的WebView加載HTML網頁時,如果html頁面中存在輸入框。那麼在有些手機設備中,當輸入框獲取焦點時,系統輸入法鍵盤無法正確彈出,從