资讯专栏INFORMATION COLUMN

关于Android消息机制的那些事儿

lushan / 1539人阅读

摘要:关于中的消息机制就进行到这里,下一篇将讲讲中的内存泄漏问题以及处理方法。

这几天对handler有一些研究,写出来供大家看看。
一、消息机制详解
Android程序中,主要是通过消息机制来推动整个程序运作的。而消息机制中,完成主要功能的主要有以下几个类:
1、Looper
2、Message、MessageQueue
3、handler
这是最基础的几个消息机制类,下面探究一下这几个类如何完成Android消息机制的运行。
首先看Message和MessageQueue。Message顾名思义,是消息机制中消息的载体,继承Parcelable序列化接口,可以在进程和组件之间作为消息的载体传播消息。而MessageQueue就是承载message的队列。关于Message,主要有以下几点总结:
1、Message中是持有Handler对象,作为Message的target的。这也很好理解,为了发送消息给handler嘛~这里要注意的一点是,Message中持有handler,而handler一般是持有Context的,所以这里是有可能引发内存泄漏的,后面会对这点进行进一步讲解。


有了target之后,message就可以调用:


还有
public void sendToTarget() {
target.sendMessage(this);
} //发送消息到target handler
2、Message中有四个参数:
public int what
public int arg1
public int arg2
public Object obj
what参数是消息的识别码,用于给handler判断不同的Message,采取不同的处理方法,这个不用多说了。
arg1和arg2都是一些携带在message中的int消息,相比setData(bundle)更加轻量级。
obj是message中可以承载的对象,注意要实现Parcelable接口。
3、Message中的recyle方法是用于当message被消费后,对message进行回收的。这个方法也蛮重要的,正是因为message会自己回收自己,才避免了很多内存泄漏的问题。
4、接下来看看MessageQuene。MessageQueue是承载Message的队列,其中最重要的方法是next方法,这个方法的作用是返回队列中下一个message。

接下来看看Looper。Looper我觉得是消息机制中最核心的类,起到了推动整个消息机制运行的作用。
looper中的主要有以下四个方法:
public static prepare();
public static myLooper();
public static loop();
public void quit();

prepare方法代码如下:
  


private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

这个方法可以理解为为本现场初始化队列消息,每个线程要使用looper进行消息循环时,都要先调用perpare方法。

myLooper方法用于返回当前消息队列的线程。注意,一个消息队列只能有一个线程。

Looper中最重要的是loop方法,调用这个方法,整个队列遍开始循环。下面看看loop方法的代码:
  

public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn"t called on this thread.");
}
final MessageQueue queue = me.mQueue;

// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();

for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}

// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}

msg.target.dispatchMessage(msg);

if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}

// Make sure that during the course of dispatching the
// identity of the thread wasn"t corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}

msg.recycleUnchecked();
}
}

可以看到,loop方法中不断地从消息队列mQueue中去获取下一个要处理的消息msg,如果消息的target成员变量为null,就表示要退出消息循环了

否则的话就要调用这个target对象的dispatchMessage成员函数来处理这个消息,这个target对象的类型为Handler

在上面的代码中,msg调用了它的target的dispatchMessage方法,实际上就是将msg丢给handler去处理了(实际上handler也没有处理,是提供接口给实现了handleMessage的具体事务类去处理)。
 接下来看看Handler。Handler主要分为SendMessage和HandleMessage两个方法,分别是发送msg和处理msg。
 SendMessage方法代码如下:
  

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

重点在最后一行加粗的代码,就是把msg装进msgqueue队列中(message肯定是持有messageQueue对象的废话)。其实发送消息实际上,也就是把消息装进消息队列中而已,因为前面的loop方法已经在不断的循环的读取msgqueue中的消息,只要把消息加进messagequeue中,就可以是消息得到处理。
再来看看消息是怎样被处理的:
  

/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}

/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

这里可以看到,实际上handler是没有处理msg的,而是给继承了handler的具体类,实现handlermessage,并对消息做出相应的处理。
我们可以看出,handler实际上并没有做什么事情,只是提供回调接口,给具体的类去实现。在使用handler的时候,可以让具体处理msg的类继承handler.Callback接口,实现handleMessage方法去处理消息。


关于Android中的消息机制就进行到这里,下一篇将讲讲handler中的内存泄漏问题以及处理方法。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64413.html

相关文章

  • 【腾讯bugly干货】关于 Android N 那些你不知道事儿

    今年3月,Google 破天荒提前半年发布了 Android N 开发者预览版。当然,作为一个不合格的谷粉并没有第一时间体验安装,因为至今仍然能够回忆起来去年今日此门中(雾)兴冲冲刷了 Android M Preview 的时候发现各种 Crash 就连微信也(不出所料得)中招时自己一脸懵逼的心情。当然,为自己的机智而庆幸并没有过多久,很快就有微信好友(当然也是纯纯的谷粉)反馈微信又双叒叕在 An...

    zombieda 评论0 收藏0
  • Win10应用设计那些事儿

    摘要:如何挑选合适的导航结构导航设计是应用设计的关键,设计规范以下简称规范中将导航元素分为对等层次和历史导航等几类,例如表和透视表导航窗格是对等导航元素,中心大纲细节属于分层导航元素,返回则属于历史导航元素。 此文已由作者杨凯明授权网易云社区发布。 欢迎访问网易云社区,了解更多网易技术产品运营经验。 继Windows 10系统发布之后,很多Windows用户更新了系统。win10系统的发布,...

    ad6623 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<