Communicating with the UI Thread

1.This lesson teaches you to

  1. Define a Handler on the UI Thread
  2. Move Data from a Task to the UI Thread

2.You should also read

3.Try it out

  DOWNLOAD THE SAMPLE  ThreadSample.zip

  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.

4.Define a Handler on the UI Thread

  Handler is part of the Android system's framework for managing threads. A Handler object receives messages and runs code to handle the messages. Normally, you create a Handler for a new thread, but you can also create a Handler that's connected to an existing thread. When you connect a Handler to your UI thread, the code that handles messages runs on the UI thread.

  Instantiate the Handler object in the constructor for the class that creates your thread pools, and store the object in a global variable. Connect it to the UI thread by instantiating it with the Handler(Looper)constructor. This constructor uses a Looper object, which is another part of the Android system's thread management framework. When you instantiate a Handler based on a particular Looper instance, theHandler runs on the same thread as the Looper. For example:

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

  Inside the Handler, override the handleMessage() method. The Android system invokes this method when it receives a new message for a thread it's managing; all of the Handler objects for a particular thread receive the same message. For example:

       /*
* 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.

5.Move Data from a Task to the UI Thread

  To move data from a task object running on a background thread to an object on the UI thread, start by storing references to the data and the UI object in the task object. Next, pass the task object and a status code to the object that instantiated the 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.

 // 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,
,
imageBuffer.length,
bitmapOptions
);
...
// Sets the ImageView Bitmap
mPhotoTask.setImage(returnBitmap);
// Reports a status of "completed"
mPhotoTask.handleDecodeState(DECODE_STATE_COMPLETED);
...
}
...
}
...

  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:

 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);
}
...
}

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:

 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;
...
}
...
}

  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:

  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);
}
...
}
...
}
...
}
...
}
 

Android 线程池系列教程(5)与UI线程通信要用Handler的更多相关文章

  1. Android 线程池系列教程(3) 创建线程池

    Creating a Manager for Multiple Threads 上一课  下一课 1.This lesson teaches you to Define the Thread Pool ...

  2. Android 线程池系列教程(2)Thread,Runnable是基类及如何写Run方法

    Specifying the Code to Run on a Thread 上一课   下一课 1.This lesson teaches you to Define a Class that Im ...

  3. Android 线程池系列教程(1)目录

    Sending Operations to Multiple Threads 1.Dependencies and prerequisites Android 3.0 (API Level 11) o ...

  4. Android 线程池系列教程(4) 启动线程池中的线程和中止池中线程

    Running Code on a Thread Pool Thread 上一课   下一课 1.This lesson teaches you to Run a Runnable on a Thre ...

  5. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  6. 《java.util.concurrent 包源码阅读》11 线程池系列之ThreadPoolExecutor 第一部分

    先来看ThreadPoolExecutor的execute方法,这个方法能体现出一个Task被加入到线程池之后都发生了什么: public void execute(Runnable command) ...

  7. Mysql线程池系列一:什么是线程池和连接池( thread_pool 和 connection_pool)

       thread_pool 和 connection_pool 当客户端请求的数据量比较大的时候,使用线程池可以节约大量的系统资源,使得更多的CPU时间和内存可以高效地利用起来.而数据库连接池的使用 ...

  8. C# 多线程学习系列三之CLR线程池系列之ThreadPool

    一.CLR线程池 1.进程和CLR的关系一个进程可以只包含一个CLR,也可以包含多个CLR2.CLR和AppDomain的关系一个CLR可以包含多个AppDomain3.CLR和线程池的关系一个CLR ...

  9. java线程池系列(1)-ThreadPoolExecutor实现原理

    前言 做java开发的,一般都避免不了要面对java线程池技术,像tomcat之类的容器天然就支持多线程. 即使是做偏后端技术,如处理一些消息,执行一些计算任务,也经常需要用到线程池技术. 鉴于线程池 ...

随机推荐

  1. IntelliJ 中类似于Eclipse ctrl+q的是Ctrl+Shift+Backspace

    IntelliJ 中类似于Eclipse ctrl+q的是Ctrl+Shift+Backspace 回到刚刚编辑的地方: ctrl+alt+Left 是回到刚刚浏览的地方,不一定是编辑的地方,可能已经 ...

  2. [RxJS] Implement RxJS `concatMap` by Waiting for Inner Subscriptions to Complete

    Unlike mergeMap and switchMap, concatMap focuses on when "inner" subscriptions "compl ...

  3. HTC 328T 如何恢复出厂设置

    设置-存储-恢复出厂设置(在存储的最下面,往下拉)

  4. MySQL基础笔记(六) 存储过程与函数

    写在开头:本文所有的示例都是基于workers表,表中保存了某公司的员工姓名.性别.工资.年龄和居住城市,如下: +----+-----------+--------+--------+------+ ...

  5. LoadRunner 事务响应时间的组成

    事务时间 一个事务的时间是指持续时间,事务会完全记录下从事务开始到事务结束之间的时间差,那么事务的时间能真实地反映业务操作的时间吗?不能,就好像人用手按秒表来记录短跑时间一样,得出的时间并不是完全准确 ...

  6. 【转载】How browsers work--Behind the scenes of modern web browsers (前端必读)

    浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工 作原理,我们将看到,从你在地址栏输入google.com到你看到google主页过程中都发生了什么. 将讨论的浏览器 今天,有五种主流浏览器- ...

  7. iOS 沙盒文件操作

    //获得document +(NSString *)documentsPath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDoc ...

  8. C语言细节笔记2

    C语言常见问题笔记:    1. 指针的声明     char * p1, p2;  p1 是一个指向char类型的指针,而p2是一个char类型变量  这是由于 * 并不是基本类型的一部分,而是包含 ...

  9. iOS开发中正则式的使用

    iOS开发中正则式的使用 第一:常规的使用方式 NSString *str = @"abcded111093212qweqw"; //找到内部一个即可 NSString *patt ...

  10. C# 中串口通信 serialport1.DataReceived 函数无法触发或者出发延时等等问题解决方法

    以前这个问题困扰我多天最后查资料一大堆,最后最终攻克了,看到非常多人做C#串口都遇到相同的问题,所以写一篇博文,以便学习交流. 一定要在com实例化的时候设置ReceivedBytesThreshol ...