Android 线程池系列教程(5)与UI线程通信要用Handler
1.This lesson teaches you to
2.You should also read
3.Try it out
In the previous lesson you learned how to start a task on a thread managed by ThreadPoolExecutor
. This final lesson shows you how to send data from the task to objects running on the user interface (UI) thread. This feature allows your tasks to do background work and then move the results to UI elements such as bitmaps.
Every app has its own special thread that runs UI objects such as View
objects; this thread is called the UI thread. Only objects running on the UI thread have access to other objects on that thread. Because tasks that you run on a thread from a thread pool aren't running on your UI thread, they don't have access to UI objects. To move data from a background thread to the UI thread, use a Handler
that's running on the UI thread.
5.Move Data from a Task to the UI Thread
Handler
. In this object, send a Message
containing the status and the task object to the Handler
. Because Handler
is running on the UI thread, it can move the data to the UI object.
5.1Store data in the task object
For example, here's a Runnable
, running on a background thread, that decodes a Bitmap
and stores it in its parent object PhotoTask
. The Runnable
also stores the status code DECODE_STATE_COMPLETED
.
1 // A class that decodes photo files into Bitmaps 2 class PhotoDecodeRunnable implements Runnable { 3 ... 4 PhotoDecodeRunnable(PhotoTask downloadTask) { 5 mPhotoTask = downloadTask; 6 } 7 ... 8 // Gets the downloaded byte array 9 byte[] imageBuffer = mPhotoTask.getByteBuffer(); 10 ... 11 // Runs the code for this task 12 public void run() { 13 ... 14 // Tries to decode the image buffer 15 returnBitmap = BitmapFactory.decodeByteArray( 16 imageBuffer, 17 0, 18 imageBuffer.length, 19 bitmapOptions 20 ); 21 ... 22 // Sets the ImageView Bitmap 23 mPhotoTask.setImage(returnBitmap); 24 // Reports a status of "completed" 25 mPhotoTask.handleDecodeState(DECODE_STATE_COMPLETED); 26 ... 27 } 28 ... 29 } 30 ...
PhotoTask
also contains a handle to the ImageView
that displays the Bitmap
. Even though references to the Bitmap
and ImageView
are in the same object, you can't assign the Bitmap
to the ImageView
, because you're not currently running on the UI thread.
Instead, the next step is to send this status to the PhotoTask
object.
5.2 Send status up the object hierarchy
PhotoTask
is the next higher object in the hierarchy. It maintains references to the decoded data and theView
object that will show the data. It receives a status code from PhotoDecodeRunnable
and passes it along to the object that maintains thread pools and instantiates Handler
:
1 public class PhotoTask { 2 ... 3 // Gets a handle to the object that creates the thread pools 4 sPhotoManager = PhotoManager.getInstance(); 5 ... 6 public void handleDecodeState(int state) { 7 int outState; 8 // Converts the decode state to the overall state. 9 switch(state) { 10 case PhotoDecodeRunnable.DECODE_STATE_COMPLETED: 11 outState = PhotoManager.TASK_COMPLETE; 12 break; 13 ... 14 } 15 ... 16 // Calls the generalized state method 17 handleState(outState); 18 } 19 ... 20 // Passes the state to PhotoManager 21 void handleState(int state) { 22 /* 23 * Passes a handle to this task and the 24 * current state to the class that created 25 * the thread pools 26 */ 27 sPhotoManager.handleState(this, state); 28 } 29 ... 30 }
5.3 Move data to the UI
From the PhotoTask
object, the PhotoManager
object receives a status code and a handle to thePhotoTask
object. Because the status is TASK_COMPLETE
, creates a Message
containing the state and task object and sends it to the Handler
:
1 public class PhotoManager { 2 ... 3 // Handle status messages from tasks 4 public void handleState(PhotoTask photoTask, int state) { 5 switch (state) { 6 ... 7 // The task finished downloading and decoding the image 8 case TASK_COMPLETE: 9 /* 10 * Creates a message for the Handler 11 * with the state and the task object 12 */ 13 Message completeMessage = 14 mHandler.obtainMessage(state, photoTask); 15 completeMessage.sendToTarget(); 16 break; 17 ... 18 } 19 ... 20 }
Finally, Handler.handleMessage()
checks the status code for each incoming Message
. If the status code isTASK_COMPLETE
, then the task is finished, and the PhotoTask
object in the Message
contains both aBitmap
and an ImageView
. Because Handler.handleMessage()
is running on the UI thread, it can safely move the Bitmap
to the ImageView
:
1 private PhotoManager() { 2 ... 3 mHandler = new Handler(Looper.getMainLooper()) { 4 @Override 5 public void handleMessage(Message inputMessage) { 6 // Gets the task from the incoming Message object. 7 PhotoTask photoTask = (PhotoTask) inputMessage.obj; 8 // Gets the ImageView for this task 9 PhotoView localView = photoTask.getPhotoView(); 10 ... 11 switch (inputMessage.what) { 12 ... 13 // The decoding is done 14 case TASK_COMPLETE: 15 /* 16 * Moves the Bitmap from the task 17 * to the View 18 */ 19 localView.setImageBitmap(photoTask.getImage()); 20 break; 21 ... 22 default: 23 /* 24 * Pass along other messages from the UI 25 */ 26 super.handleMessage(inputMessage); 27 } 28 ... 29 } 30 ... 31 } 32 ... 33 } 34 ... 35 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?