Handler是androd中必须学会的内容,其实使用是非常简单的,不过有必要再啰嗦一下,算是复习:
Android的UI操作并不是线程安全,因此启动线程访问用户界面的UI组件是不被允许的,handler解决了这个问题,使用了如下手段:
1.在新启动的线程中发送消息(发送到指定的messagequeue)
2.在主线程中接收消息并处理
handler负责发送消息,looper死循环负责接收消息,并把消息回传给handler自己
如果希望handler正常工作,当前线程必须要有一个messagequeue,而messagequeue是由looper管理的,也就是当前线程必须有一个looper,要想保证有looper分为两种情况:
1.在主线程(UI线程)中
2.在非主线程中
创建Handler也就可以分为两种方法:
new Handler(); //没有指定Looper,那么默认Looper为当前线程
new Handler(Looper looper); //指定looper为参数looper
那么这两种方式使用的场景在哪里呢,根据使用经验,我认为如下:
①在主线程中创建Handler,直接new一个不带参数的Handler好像没什么问题,实现handleMessage即可。
②在子线程中创建Handler,似乎要带参数,并且指定looper。
先看看什么是Looper:
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
原来Threads默认没有message loop,然而主线程是个例外,在Activity中的UI主线程中,无需使用显式的方式进行Looper的初始化以及开始循环,是因为Activity内部包含一个Looper对象,它会自动管理Looper,处理子线程中发送过来的消息。而初始化Handler的时候,在Handler的构造函数中,会把当前线程的Looper与Handler关联,所以在Activity中,无需显式使用Looper,这也就解释了我说的使用场景:主线程不带参数。
同时注意到,子线程要创建一个looper还是比较麻烦的,必须调用prepare和loop方法,谷歌文档中给出的例子是这样的:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
也不算很复杂,不过google官方已经为此提供了解决方案,也就是HandlerThread了,HandlerThread本质是就是一个普通的Thread,只不过内部建立了Looper,使用HandlerThread不用再去手动建立,它的使用是类似这样的:
mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//处理消息
}
});
创建消息的时候,似乎也有两种写法:
①Message msg=new Message();
②Message msg=mHandler.obtainMessage();
这两种写法的区别是一个是自己创建的message,一个是拿系统的message直接使用。
发送消息事实上也有两种写法:
①mHandler.sendMessage();
②message.sendToTarget();也能发送消息给handler
解决新线程不能更新UI组件的问题,使用handler实现线程通信显然是一种方法,不过不是唯一的方法,也就是异步任务AsyncTask,相对来说AsyncTask更为轻量级一些,适用于简单的异步处理.例子如下:
class DownTask extends AsyncTask<URL,Integer,String>{
protected String doInBackground(URL ... params){
//此函数处理耗时操作
}
protected String onPreExcute(URL ... params){
//在处理耗时操作前调用,可以先显示一个进度条
}
protected String onPreExcute(URL ... params){
//在处理耗时操作后被调用,下载完成了,将他显示出来的操作放在这里
}
protected String onProgressUpdate(Integer... values){
//在doInBackground中调用publishProgress会调到onProgressUpdate,
//如随着下载进度的改变更新进度值
}
}
感觉没啥思路,以上是我想到的一些。