您的位置:首页 > 移动开发 > Android开发

android中的消息机制--浅谈Handler的原理及使用

2016-06-13 21:56 591 查看
handler是什么?
首先,android中为什么需要消息机制呢?我们知道进程是一个运行的代码单元,而一个进程中又有若干个线程,线程可以并发执行,同时也可以互相通信。我们在谈论android消息机制的时候,实质上就是在谈论android中线程和线程之间该如何通信,而线程通信中最常见的应用场景就是子线程与主线程(UI线程)之间的切换,而Handler正是android提供给我们的上层接口,只要掌握了Handler的原理和用法,也就理解了android中的消息机制。

这里有必要先解释一下,为什么主线程又叫UI线程,在android中,规定UI操作必须在主线程中进行,因为UI是线程不安全的,如果放在子线程中操作,由于多线程的并发访问,可能导致无法预期的结果。而通常我们要进行网络请求等耗时操作的时候,为了不阻碍UI线程的事件分发,导致ANR,就必须起一个子线程,操作完毕后,如果需要更改UI则又必须返回主线程,消息机制就很好的解决了这个问题。

那么,为什么handler可以实现消息机制呢?一句话概括就是,handler可以让一个执行体在其所在的线程中执行。因此,要想从一个子线程切换到UI线程,只需要在子线程中将一个执行体抛到UI线程中即可。听起来挺简洁,但真正实现确并非这么简单。

消息机制的流程
当然,要实现消息机制单靠Handler还是不够的,他还有另外两个好基友:MessegeQueue和Looper,下面分别来介绍一下。
MessageQueue直译过来就是:消息队列,没错,他就是一个用于存放和管理消息的“队列”,这里之所以加引号是因为消息队列在数据结构上并不是一个队列,而是一个单链表,之所以使用单链表主要原因是,MessageQueue管理消息的主要操作方式就是插入和读取并删除,显然,链表结构非常适合。
Looper翻译过来就是:循环,他做的事情就是不断的循环拿到消息,然后交给Handler处理。
前面提到,Handler可以将子线程中的执行体抛到UI线程中,然后在UI线程中执行相应逻辑,结合上面MessageQueue和Looper的简单介绍,我们就可以梳理出消息机制的整个流程了:
1.Handler在子线程中封装一个Message,然后sendMessage,post方法实质上最后还是调用了sendMessage,只是把post参数中的Runnable封装在Message中而已,即把想要抛到UI线程中的执行体赋给了Message的成员callBack;
2.Message被发出后,来到了MessageQueue,MessageQueue先调用enqueueMessage方法将该Message插入到链表中,然后,再调用另外一个不断循环的方法next将Message取出同时在链表中删除;
3.取出之后,一直在循环“检查消息”的Looper发现有新消息,在Looper内部调用Handler的dispatchMessage方法处理Message。由于Looper所在的线程就是主线程,调用的dispatchMessage方法自然就能让执行体在UI线程中进行了,从而达到了线程切换的效果。
下面的图描述了消息机制的整个流程:



这里需要说明一下,我们在创建Handler的线程中,必须要有一个Looper,当然,由于主线程(ActivityThread)初始化时已经自动生成了Looper,而在主线程之外,则需要我们手动调用Looper.prepare()来创建Looper,然后Looper.loop(),如果没有Looper,sendMessage将返回false。
与创建对应的就是qiut,由于Looper干的事情就是检查新消息,然后处理,在没有新消息时,Looper处于阻塞状态,如果不手动qiut(qiutSafely)的话,线程就会一直处于等待状态。因此,必须在所有消息处理完毕后,调用qiut,从而通知MessageQueue调用qiut并退出,此时next方法会返回null,Looper结束。

另外,在处理消息时,通常的处理顺序为:
1.判断Message的Callback是否为空,Callback就是post方法中的Runnable,如果以post的方式抛出执行逻辑,就执行这个逻辑;
2.判断Handler的构造函数中的参数callback,我们通常采用派生Handler子类,重写handleMessage的方法来创建Handler,其实这里还有一种方式,使用含参数callback的构造函数创建Handler,重写里面的handleMessage,这样就不需要派生子类,如果是这样,就调用callback中的handleMessage;
3.如果前两个条件都不满足,调用Handler的handleMessage方法。

以上就是消息机制的实现流程及相关细节,接下来,我们看两个handler的常规用法:
当然,除了以下两种用法外,View的post方法和Activity的runOnUiThread方法也可以在子线程中进行UI操作,但归根结底他们内部还是通过Handler的post方法实现。

<pre class="java" name="code">public class MainActivity extends Activity {

private Handler handler;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
// 在这里进行UI操作
}
});
}
}).start();
}
}
<span style="font-size:14px;"></span>
<pre class="java" name="code"><pre class="java" name="code">public class MainActivity extends Activity {

private Handler handler;
private TextView tv;

@Override
protected void onCreate(Bundle savedInstance
8f1e
State) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
tv = (TextView)findViewById(R.id.tv);

handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == 1)
tv.setText("helloWorld!");
}
};

new Thread(new Runnable() {
@Override
public void run() {
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
});
}
}




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: