介绍
在平时的安卓开发过程中,Handler一定不少见,Handler是Android消息机制的上层接口,这使得在开发过程中只需要和Handler交互即可。很多人认为Handler的作用就是更新UI,的确没错,但是更新UI仅仅是Handler的一个特殊的使用场景。具体来说,就是有时候需要在子线程做一些耗时操作,比如说访问网络或者耗时的I/O操作,当这些耗时操作完成时,程序的UI进行相应的改变。由于安卓开发规范的限制,我们不能在子线程中访问UI控件,因为UI的控件是线程非安全的,这个时候通过Handler就可以将更新UI的操作切换到主线程中执行。下面我就通过代码来演示Handler的基本用法。
基本用法
我这里先上代码,以下是最基本的用法
public class MainActivity extends AppCompatActivity {
private TextView textView;
private String TAG = "MainActivity";
private int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
}
public void onClick(View v){
++i;
//创建新的线程
new Thread(){
@Override
public void run() {
super.run();
doSendMsg();
}
}.start();
}
/**
* 在子线程中做耗时操作,完成之后,通知Handler更新UI
*/
private void doSendMsg(){
try {
Thread.sleep(1000);//模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = Message.obtain();
message.arg1 = i;
message.what = 1;
mHandler.sendMessage(message);
}
Handler mHandler = new Handler(){
/**
* handleMessage接收消息后进行相应的处理
* @param msg
*/
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1){
textView.setText(msg.arg1+"");
}
}
};
}
以下是运行效果:
以上代码是Handler里的最基本的操作了,相信读者非常容易看懂。不过我还是解释一下,首先按钮响应了点击事件之后,创建了一个新的线程,模拟耗时操作让线程休眠了1秒钟,操作完成之后将需要传递的数据装入Message对象,再通过mHandler.sendMessage()方法将消息发送出去,此时实现了Handler的handleMessage()方法就能够接收到此消息,这时候已经是在UI线程了,所以能够在方法里面进行相应的UI更新。以上是最典型的Handler更新UI操作,至于Handler的其他用法,可以参考官方文档,里面有非常详细全面的解释.
https://developer.android.com/reference/android/os/Handler.html
原理解析
那么Handler是怎么工作的呢?这时候需要认识这三个类,分别是: Message(消息), MessageQueue(消息队列), Looper(消息循环者)。
- Message :android.os.Message是定义一个Messge包含必要的描述和属性数据,并且此对象可以被发送给android.os.Handler处理。属性字段:arg1、arg2、what、obj、replyTo等;其中arg1和arg2是用来存放整型数据的;what是用来保存消息标示的;obj是Object类型的任意对象;replyTo是消息管理器,会关联到一个handler,handler就是处理其中的消息。通常对Message对象不是直接new出来的,只要调用handler中的obtainMessage方法来直接获得Message对象。
- MessageQueue :MessageQueue的中文翻译是消息队列,顾名思义,它的内部存储了一组消息,以队列的形式对外提供插入和删除的工作。虽然叫消息队列,但是它的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息。它只是用来存储消息,而并不能处理消息,Looper就填补了这个功能。
- Looper:在MessageQueue里存储了消息之后,Looper就会以无限循环的形式去查是否有新消息,如果有的话就去处理消息,否则就是一直等待着。Looper中还有一个特殊的概念就是ThreadLocal,ThreadLocal并不是线程,它是用来在每个线程中存储数据。Handler创建的时候就会采用ThreadLocal获取当前线程的Looper构造消息循环系统。还有一点非常要注意的是,工作线程是默认是没有Looper的,若要在线程中使用就需要创建Looper,否则就会抛出Can’t create handler inside thread that has not called Looper.prepare(),意思是不能创建Handler因为Looper没有执行Looper.prepare()方法,尚未初始化。而UI线程即主线程中,是默认初始化了Looper的,所以不需要再UI线程再次执行Looper.prepare()方法了。那么在工作线程中如何初始化Looper的代码如下:
new Thread("Thread#2"){
@Override
public void run(){
Looper.prepared();
Handler handler = new Handler();
Looper.loop();
};
}.start();
工作流程
Handler的主要工作包含消息的发送与接收过程。消息的发送通过post和send的一系列方法来实现,其实post的一系列方法最终还是通过send来实现的。当Handler发送了消息之后,MessageQueue里就插入了一条消息,然后MessageQueue就会返回这条消息给Looper,Looper接收到消息之后就开始处理了,最终消息由Looper交给Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入了处理消息的阶段,最后经过一系列的判断之后,就会调用handleMessage()方法了。
以上就是Handler机制的基本原理,相信通过上面介绍之后,读者对Handler能够有更清楚的认识。