android异步消息处理机制

如果尝试在程序里创建两个Handler对象,一个在主线程中创建,一个在子线程创建.

public class MainActivity extends ActionBarActivity {

private Handler mh1;

private Handler mh2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mh1=new Handler();

new Thread(new Runnable() {

@Override

public void run() {

mh2=new Handler();

}

}).start();

}

}

运行程序会发现,在子线程中创建的Handler的对象会导致程序崩溃,报错如下:



说的是不能再没有Looper.prepare()的线程中创建Handler对象.

如果在子线程中调用了Looper.prepare().

public class MainActivity extends ActionBarActivity {

private Handler mh1;

private Handler mh2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mh1=new Handler();

new Thread(new Runnable() {

@Override

public void run() {

Looper.prepare();

mh2=new Handler();

}

}).start();

}

再运行.就不会出现这个问题了.

看看Handler的无参构造函数.

public Handler() {

if (FIND_POTENTIAL_LEAKS) {

final Class<? extends Handler> klass = getClass();

if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&

(klass.getModifiers() & Modifier.STATIC) == 0) {

Log.w(TAG, "The following Handler class should be static or leaks might occur: " +

klass.getCanonicalName());

}

}

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can‘t create handler inside thread that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = null;

}

可以看到   ,mLooper是Looper的对象,如果mLooper为空,就会抛出一个运行异常.提示的错误正是刚才运行的错误.

再看一下,什么时候Looper对象才为空

public static final Looper myLooper() {

return (Looper)sThreadLocal.get();

}

方法很简单,就是从sThreadLocal取出Looper,如果sThreadLocal存在Looper则返回looper对象,否则返回空.

结合上面运行,第一遍因为没有Looper.prepare()方法而报Looper对象为空,  第二遍因为有了Looper.prepare()而不会出现这种情况.

所以sThreadLocal里面的Looper对象肯定是Looper.prepare()方法传进去的.

Looper.prepare()方法源码:

public static final void prepare() {

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

sThreadLocal.set(new Looper());

}

在这里,可以看到sThreadLocal首先判断是否有Looper对象,如果已经有了,则抛出异常,否则创建一个Looper对象set进去.

看出,每个线程中最多只能有一个Looper对象.

看看刚才的代码,发现只有子线程中调用了Looper.prepare()方法,主线程并没有调用.

这是因为在程序启动时,系统已经自动调用了Looper.prepare()方法.

查看ActivityThread中的main()方法

public static void main(String[] args) {

SamplingProfilerIntegration.start();

CloseGuard.setEnabled(false);

Environment.initForCurrentUser();

EventLogger.setReporter(new EventLoggingReporter());

Process.setArgV0("<pre-initialized>");

Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();

thread.attach(false);

if (sMainThreadHandler == null) {

sMainThreadHandler = thread.getHandler();

}

AsyncTask.init();

if (false) {

Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));

}

Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");

}

可以看到这里有一个Looper.prepareMainLooper()方法.再看到这个方法内部

public static final void prepareMainLooper() {

prepare();

setMainLooper(myLooper());

if (Process.supportsProcesses()) {

myLooper().mQueue.mQuitAllowed = false;

}

}

到这里,已经明白:主线程中始终会存在一个Looper对象,而在子线程中需要调用Looper.prepare()去创建.

再看Handler是如何发送消息

public class MainActivity extends ActionBarActivity {

private Handler mh1;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mh1=new Handler();

new Thread(new Runnable() {

@Override

public void run() {

Message meg=Message.obtain();

meg.obj="data";

mh1.sendMessage(meg);

}

}).start();

}

}

在线程中,用Handler对象发送一个Message.

可是,Handler到底是把Message发送到哪里?为什么又会在Handler的handleMessage()方法中可以获取这条Message.

其实Handler提供了多个发送消息的方法,除了sendMessageAtFrontOfQueue()外,所有方法都到经过sendMessageAtTime()方法.

sendMessageAtTime()源码如下:

public boolean sendMessageAtTime(Message msg, long uptimeMillis)

{

boolean sent = false;

MessageQueue queue = mQueue;

if (queue != null) {

msg.target = this;

sent = queue.enqueueMessage(msg, uptimeMillis);

}

else {

RuntimeException e = new RuntimeException(

this + " sendMessageAtTime() called with no mQueue");

Log.w("Looper", e.getMessage(), e);

}

return sent;

}

方法接受两个参数,第一个就是Message对象,第二个则是需要延迟发送的毫秒数.如果不是调用的sendMessageDelayed(),延迟数都为0.

MessageQueue,是一个消息队列.提供了出队与入队的方法.

而这里面的enqueueMessage就是入队方法.

final boolean enqueueMessage(Message msg, long when) {

if (msg.when != 0) {

throw new AndroidRuntimeException(msg + " This message is already in use.");

}

if (msg.target == null && !mQuitAllowed) {

throw new RuntimeException("Main thread not allowed to quit");

}

synchronized (this) {

if (mQuiting) {

RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");

Log.w("MessageQueue", e.getMessage(), e);

return false;

} else if (msg.target == null) {

mQuiting = true;

}

msg.when = when;

Message p = mMessages;

if (p == null || when == 0 || when < p.when) {

msg.next = p;

mMessages = msg;

this.notify();

} else {

Message prev = null;

while (p != null && p.when <= when) {

prev = p;

p = p.next;

}

msg.next = prev.next;

prev.next = msg;

this.notify();

}

}

return true;

}

MessageQueue并没有使用一个集合将所有的消息保存起来,它只使用了mMessages对象表示未处理的消息.

其实入队的方法就是将所有的消息按uptimeMillis时间排序,具体操作方法根据时间顺序调用msg.next.

而从每一个消息指定它的下一个消息是什么.

而出队的方法,就在Looper.loop()方法.

public static final void loop() {

Looper me = myLooper();

MessageQueue queue = me.mQueue;

while (true) {

Message msg = queue.next(); // might block

if (msg != null) {

if (msg.target == null) {

return;

}

if (me.mLogging!= null) me.mLogging.println(

">>>>> Dispatching to " + msg.target + " "

+ msg.callback + ": " + msg.what

);

msg.target.dispatchMessage(msg);

if (me.mLogging!= null) me.mLogging.println(

"<<<<< Finished to    " + msg.target + " "

+ msg.callback);

msg.recycle();

}

}

}

从代码的  while(true)  开始就是一个死循环,然后不停的调用MessageQueue的next方法,next()就是消息队列出队的方法.

它的简单逻辑就是如果当前MessageQueue中存在mMessages(待处理消息) ,就将这个消息出队,然后让下一个消息成为mMessages,否则就形成一个堵塞状态,一直等到有新消息入队.

每当一个消息出队,就将它传递到msg.target的dispatchMessage()方法中.

而msg.target就是Handler对象.

public void dispatchMessage(Message msg) {

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

如果mCallback不为空,则调用mCallBack的handleMessage()方法,否则调用Handler的handleMessage()方法.

除了发送消息,还有几种方法可以在子线程中更新UI

1.Handler的post()方法

2.View的post()方法

3.Activity的runOnUiThread()方法.

来自为知笔记(Wiz)

时间: 2024-12-09 07:55:28

android异步消息处理机制的相关文章

Android异步消息处理机制(3)asyncTask基本使用

本文翻译自android官方文档,结合自己测试,整理如下. 概述 AsyncTask抽象类,翻译过来就是异步任务,能够合理并方便的使用UI线程.该类可以实现将后台操作结果显示在UI线程中,而不需要我们自己实现子线程或者handler(当然它内部也是借助这两者实现的). 虽然AsyncTask可以提供后台运行并将结果显示在UI上,但是理想情况应该是后台操作最多只能是几秒钟,若要执行长时间的操作强烈建议使用java中的Executor,ThreadPoolExecutor,FutureTask等.

[学习总结]6、Android异步消息处理机制完全解析,带你从源码的角度彻底理解

开始进入正题,我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃.相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟于心,即创建一个Message对象,然后借助Handler发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后在这里进行UI操作就不会再出现崩溃了. 这种处理方式被称为异步消息处理线程,虽然我相信大家都会用,可是你知道它背后的原理是什么样的吗?今天我们就来一起

Android异步消息处理机制(4)AsyncTask源码解析

上一章我们学习了抽象类AsyncTask的基本使用(地址:http://blog.csdn.net/wangyongge85/article/details/47988569),下面我将以问答的方法分析AsyncTask源码内容,源码版本为:API22. 1. 为什么必须在UI线程实例化我们的AsyncTask,并且必须在主线程中调用execute(Params... params)? 在分析为什么在UI线程调用之前,我们先看一下实例化AsyncTask并调用execute(Params...

Android异步消息处理机制详解及源码分析

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 最近相对来说比较闲,加上养病,所以没事干就撸些自己之前的知识点为博客,方便自己也方便别人. 1 背景 之所以选择这个知识点来分析有以下几个原因: 逛GitHub时发现关注的isuss中有人不停的在讨论Android中的Looper , Handler , Me

Android异步消息处理机制(2)源码解析

上一章讲解了Android异步消息处理机制的基本使用,下面将简单地探寻一下异步机制背后的奥妙,源码版本为:API22. 首先,声明一下本文是在我参考了一下各位大神的文章之后才慢慢熟悉的, 若有不足之处,还望各位批评指正!.菜鸟上路,,,, 郭霖博客 鸿洋博客 刘超 深入解析android5.0系统 任玉刚博客 先后顺序按照拼音排序,无关技术本身. 先简单地总结一下Looper,MessageQueue,Message和Handler四者之间的关系: Looper和MessageQueue Loo

Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Android中的Looper , Handler , Message有什么关系?本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论. 1. 概述 Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念.那么什么叫异步消息处理线程呢?异步

Android异步消息处理机制——handle与Looper,AsyncTask

Android线程间的通讯采用异步消息处理机制,主要由四部分组成,包括Message,Handler,MessageQueue和Looper. 一个线程只有一个Looper与Messagequeue,但可以有多个handler实例. 例:线程A发消息Message,线程B处理消息Message. 需要在线程B中新建一个Handler实例handler,在A线程中通过该handler发送消息到线程B中的Messagequeue中, 通过B中的Looper以及先进先出的原则取出该消息并处理消息,所以

Android 异步消息处理机制

转载自博客:http://blog.csdn.net/lmj623565791/article/details/38377229/ 1. 概述 Handler . Looper .Message 这三者都与Android异步消息处理线程相关的概念.那么什么叫异步消息处理线程呢?异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环.若消息队列为空,线程则会阻塞等待. 说了这一堆,那么和Handler

Android异步消息处理机制完全解析,带你从源码的角度彻底理解

转载于:http://blog.csdn.net/guolin_blog/article/details/9991569 之前也是由于周末通宵看TI3比赛,一直没找到时间写博客,导致已经有好久没更新了.惭愧!后面还会恢复进度,尽量保证每周都写吧.这里也是先恭喜一下来自瑞典的Alliance战队夺得了TI3的冠军,希望明年中国战队能够虎起! 开始进入正题,我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃.相信大家在日常的工作当中都会经常遇到这个问题

【转】Android异步消息处理机制完全解析,带你从源码的角度彻底理解

原文网址:http://blog.csdn.net/guolin_blog/article/details/9991569 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9991569 之前也是由于周末通宵看TI3比赛,一直没找到时间写博客,导致已经有好久没更新了.惭愧!后面还会恢复进度,尽量保证每周都写吧.这里也是先恭喜一下来自瑞典的Alliance战队夺得了TI3的冠军,希望明年中国战队能够虎起! 开始进入正题,我们都知道,