android线程相关1

 

android中的Handler
对于这部分的内容,将分成4 小节来描述:
1)职责与关系
2)消息循环
3)线程与更新
4)几点小结
----------------------------------------------------------------------------------------------
1) 接下来,我们开始这部分的内容,首先了解一下各自的职责及相互之间的关系。
职责
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue 统一列队,终由               Handler 处理。
Handler:处理者,负责Message 的发送及处理。使用Handler 时,需要实现handleMessage(Message msg)      方法来对特定的Message 进行处理,例如更新UI 等。
MessageQueue:消息队列,用来存放Handler 发送过来的消息,并按照FIFO 规则执行。当然,存放Message      并非实际意义的保存,而是将Message 以链表的方式串联起来的,等待Looper 的抽取。
Looper:消息泵,不断地从MessageQueue 中抽取Message 执行。因此,一个MessageQueue 需要一Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

关系
    class Class Model
    Looper MessageQueue
    Handler
Handler,Looper 和MessageQueue 就是简单的三角关系。Looper 和MessageQueue 一
一对应,创建一个Looper 的同时,会创建一个MessageQueue。而Handler 与它们的关
系,只是简单的聚集关系,即Handler 里会引用当前线程里的特定Looper 和MessageQueue。
这样说来,多个Handler 都可以共享同一Looper 和MessageQueue 了。当然,这些
Handler 也就运行在同一个线程里。

2) 接下来,我们简单地看一下消息的循环过程:
生成
Message msg = mHandler.obtainMessage();
msg.what = what;
msg.sendToTarget();

发送
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
在Handler.java 的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看
到,它找到它所引用的MessageQueue,然后将Message 的target 设定成自己(目的是
为了在处理消息环节,Message 能找到正确的Handler),再将这个Message 纳入到消
息队列中。

抽取
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
在Looper.java 的loop()函数里,我们看到,这里有一个死循环,不断地从
MessageQueue 中获取下一个(next 方法)Message,然后通过Message 中携带的
target 信息,交由正确的Handler 处理(dispatchMessage 方法)。

处理
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
在Handler.java 的dispatchMessage(Message msg)方法里,其中的一个分支就是调用
handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler
时需要实现handleMessage(Message msg)的原因。
至于dispatchMessage 方法中的另外一个分支,我将会在后面的内容中说明。
至此,我们看到,一个Message 经由Handler 的发送,MessageQueue 的入队,Looper
的抽取,又再一次地回到Handler 的怀抱。而绕的这一圈,也正好帮助我们将同步操作
变成了异步操作。

3) 剩下的部分,我们将讨论一下Handler 所处的线程及更新UI 的方式。
在主线程(UI 线程)里,如果创建Handler 时不传入Looper 对象,那么将直接使用主
线程(UI 线程)的Looper 对象(系统已经帮我们创建了);在其它线程里,如果创建
Handler 时不传入Looper 对象,那么,这个Handler 将不能接收处理消息。在这种情况
下,通用的作法是:
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();
}
}
在创建Handler 之前,为该线程准备好一个Looper(Looper.prepare),然后让这个
Looper 跑起来(Looper.loop),抽取Message,这样,Handler 才能正常工作。
因此,Handler 处理消息总是在创建Handler 的线程里运行。而我们的消息处理中,不
乏更新UI 的操作,不正确的线程直接更新UI 将引发异常。因此,需要时刻关心
Handler 在哪个线程里创建的。

如何更新UI 才能不出异常呢?SDK 告诉我们,有以下4 种方式可以从其它线程访问UI
线程:
· Activity.runOnUiThread(Runnable)
· View.post(Runnable)
· View.postDelayed(Runnable, long)
· Handler
其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里,
View 获得当前线程(即UI 线程)的Handler,然后将action 对象post 到Handler 里。
在Handler 里,它将传递过来的action 对象包装成一个Message(Message 的callback
为action),然后将其投入UI 线程的消息循环中。在Handler 再次处理该Message 时,
有一条分支(未解释的那条)就是为它所设,直接调用runnable 的run 方法。而此时,
已经路由到UI 线程里,因此,我们可以毫无顾虑的来更新UI。

4)  几点小结
· Handler 的处理过程运行在创建Handler 的线程里
· 一个Looper 对应一个MessageQueue
· 一个线程对应一个Looper
· 一个Looper 可以对应多个Handler
· 不确定当前线程时,更新UI 时尽量调用post 方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值