android学习11——Handler,Looper,MessageQueue工作原理

时间:2023-03-09 18:54:49
android学习11——Handler,Looper,MessageQueue工作原理

Message是Handler接收和处理的消息对象. 每个线程只能拥有一个Looper.它的loop方法读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理.MessageQueue是消息队列,它采用先进先出的方式来管理Message.程序创建Looper对象时会在它的构造器中创建MessageQueue对象.

下面用一个例子说明.不能在主线程中执行耗时的工作,否则会报ANP错误.常用的方法是在主线程中向子线程中发消息,交给子线程处理.看下面的例子.

public class SumThread extends Thread {
private Handler handler;
private Context context;
public SumThread(Context context) {
this.context = context;
}
@Override
public void run() {
Log.i("Logzy", "Loop prepare");
Looper.prepare();
handler = new SumHandler(context);
Looper.loop();
Log.i("Logzy", "Loop end");
} public Handler getHandler() {
return handler;
}
}

在子线程中创建一个Handler.注意在子线程中创建Handler的时候,要先创建Looper对象,并通过prepaer启动它. Looper.loop()是一个死循环,不断从MessageQueue中取出消息交给Handler处理.所以除非显式退出Looper,Log.i("Logzy", "Loop end")这行代码不会被执行.另外需要注意的一点是在主线程中,系统已经初始化一个Looper对象,因此程序直接创建Handler即可,然后就可通过Handler来发送,处理消息.主线程中创建Handler的方法见这个例子http://www.cnblogs.com/zhouyang209117/p/5108048.html

例子的源代码:https://github.com/zhouyang209117/AndroidTutorial/tree/master/Crazy/ch3/Loop

再说HandlerThread的用法.上面已经提到子线程中创建Handler的时候,要先创建Looper对象,并通过prepaer启动.HandlerThread可以将这些操作简化.看下面代码:

public class MyActivity extends Activity {
static final String UPPER_NUM = "upper";
EditText etNum;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etNum = (EditText)findViewById(R.id.etNum);
HandlerThread handlerThread = new HandlerThread("aaa");
handlerThread.start();
handler = new SumHandler(this, handlerThread.getLooper());
} public void cal(View source) {
Message msg = new Message();
msg.what = 0x123;
Bundle bundle = new Bundle();
bundle.putInt(UPPER_NUM,
Integer.parseInt(etNum.getText().toString()));
msg.setData(bundle);
handler.sendMessage(msg);
}
}

最重要的是这3行代码:

HandlerThread handlerThread = new HandlerThread("aaa");
handlerThread.start();
handler = new SumHandler(this, handlerThread.getLooper());

HandlerThread也是一个线程.通过start()启动,里面的Looper就已经初始化好了再调用handler = new SumHandler(this, handlerThread.getLooper()),可以启动Looper,不用再显式启动.这样简化了代码.

源代地址:https://github.com/zhouyang209117/AndroidTutorial/tree/master/Crazy/ch3/HandlerThread