Android后台线程和UI线程通讯实例
本节向你展示如何在任务中发送数据给ui线程里的对象,这个特性允许你在后台线程工作,完了在ui线程展示结果。
在ui线程定义一个handler
handler是android系统线程管理框架里的一部分。一个handler对象接收消息,并且运行代码来处理消息。正常情况下,你为新线程创建handler,但你也可以为已有的线程创建一个handler.当你连接handler到ui线程时,处理消息的代码会在ui线程上运行.
在创建线程池的类的构造器里实例化handler对象,保存在全局变量里。用handler(looper)方法实例化,连接到ui线程,构造方法使用looper对象,也是android系统线程管理框架里的一部分.looper类有一个静态方法getmainlooper()可以获取ui线程的looper对象。如:
private photomanager() {
...
// defines a handler object that's attached to the ui thread
mhandler = new handler(looper.getmainlooper()) {
...
在handler里,覆盖handlemessage()。android系统会在handler管理的线程收到新消息时,调用该方法。一个指定线程的所有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对象里,接下来把任务对象和状态码传给handler对象。在这个对象里,发送一个包含状态 和任务对象的消息给handler.因为handler在ui线程上运行,它可以移动数据给ui对象。
在任务对象里存储数据
如,这是一个runnable,运行在后台线程,它解析bitmap,并保存到它的父对象。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还包含一个imageview引用,用来显示bitmap.尽管引用bitmap和imageview是在同一个对象里,但因为不是在ui线程,你不能直接让imageview显示bitmap.
沿对象层次逐级发送状态
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,发送给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()为每个进来的message检查状态码。如果状态码是task_complete,任务就是完成了,message里的phototask对象包含bitmap和imageview.因为handler.handlemessage()运行在ui线程,它可以安全地为imageview设置bitmap.