当前位置: 代码迷 >> Android >> 简述android线程间消息处理机制(Looper、Handler跟Message)
  详细解决方案

简述android线程间消息处理机制(Looper、Handler跟Message)

热度:149   发布时间:2016-05-01 14:41:11.0
简述android线程间消息处理机制(Looper、Handler和Message)

?

作用:Android的线程间消息处理机制主要是用来处理主线程(UI线程)跟工作线程(自己创建的线程)间通信的,如:通过工作线程刷新界面,或者在工作线程中创建一个dialog或者Toast等。

工作线程:在android应用程序中,我们创建的ActivityServiceBroadcast等都是在主线程(UI线程)处理的,但一些比较耗时的操作,如I/O读写的大文件读写,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现ANR的响应提示窗口,这个时候我们可以考虑创建一个工作线程(继承Thread类或者实现Runnable接口)来解决。

使用工作线程容易出现的问题:对于Android平台来说UI控件都没有设计成为线程安全类型,所以需要引入一些同步的机制来使其刷新,否则使用工作线程更新UI会出现异常。

?

Looper

针对以上问题,android采用消息循环机制来处理线程间的通信,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环),Android系统中Looper负责管理线程的消息队列和消息循环, 可以通过Loop.myLooper()得到当前线程的Looper对象,通过Loop.getMainLooper()可以获得当前进程的主线程的 Looper对象。Looper对象是什么呢?其实Android中每一个Thread都对应一个LooperLooper可以帮助Thread维护一个消息队列,负责在多线程之间传递消息的一个循环器。一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper),但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。如下例所示:class LooperThread extends Thread {

public Handler mHandler;public void run() {Looper.prepare();mHandler =newHandler() {public void handleMessage(Message msg) {// process incoming messages here}};Looper.loop();}}

?

?

Looper.prepare()Looper对象的创建是通过prepare函数,而且每一个Looper对象会和一个线程关联,具体操作请见源码:

?

?

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

?

?

Looper对象创建时会创建一个MessageQueue(消息队列),主线程默认会创建一个Looper从而有MessageQueue,其他线程默认是没有 MessageQueue的,不能接收Message(消息),如果需要接收Message则需要通过prepare函数创建一个MessageQueue。具体操作请见源码。

?

?

private Looper() {           mQueue = new MessageQueue();           mRun = true;          mThread = Thread.currentThread();       }     

?

?

Looper.loop()Loop函数从MessageQueue中从前往后取出Message,然后通过HandlerdispatchMessage函数进行消息的处理(可见消息的处理是Handler负责的),消息处理完了以后通过Message对象的recycle函数放到Message Pool中,以便下次使用,通过Pool的处理提供了一定的内存管理从而加速消息对象的获取。至于需要定时处理的消息如何做到定时处理,请见 MessageQueuenext函数,它在取Message来进行处理时通过判断MessageQueue里面的Message是否符合时间要求来决定是否需要把Message取出来做处理,通过这种方式做到消息的定时处理。具体操作请见源码:

?

?

public static final void loop() {         Looper me = myLooper();          MessageQueue queue = me.mQueue;          while (true) {             Message msg = queue.next(); // might block          //if (!me.mRun) {              //    break;               //}                 if (msg != null) {                    if (msg.target == null) {                        // No target is a magic identifier for the quit message                       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();               }           }       }  

?

看next()函数

?

    final Message next() {        boolean tryIdle = true;        while (true) {            long now;            Object[] idlers = null;                // Try to retrieve the next message, returning if found.            synchronized (this) {                // is counted in milliseconds since the system was booted,not counting time spent in deep sleep.                now = SystemClock.uptimeMillis();                                Message msg = pullNextLocked(now);                if (msg != null) return msg;                if (tryIdle && mIdleHandlers.size() > 0) {                    idlers = mIdleHandlers.toArray();                }            }                // There was no message so we are going to wait...  but first,            // if there are any idle handlers let them know.            boolean didIdle = false;            if (idlers != null) {                for (Object idler : idlers) {                    boolean keep = false;                    try {                        didIdle = true;                        keep = ((IdleHandler)idler).queueIdle();                    } catch (Throwable t) {                        Log.wtf("MessageQueue", "IdleHandler threw exception", t);                    }                    if (!keep) {                        synchronized (this) {                            mIdleHandlers.remove(idler);                        }                    }                }            }                        // While calling an idle handler, a new message could have been            // delivered...  so go back and look again for a pending message.            if (didIdle) {                tryIdle = false;                continue;            }            synchronized (this) {                // No messages, nobody to tell about it...  time to wait!                try {                    if (mMessages != null) {                        if (mMessages.when-now > 0) {                            Binder.flushPendingCommands();                            this.wait(mMessages.when-now);                        }                    } else {                        Binder.flushPendingCommands();                        this.wait();                    }                }                catch (InterruptedException e) {                }            }        }    }
?

?

?

final Message pullNextLocked(long now) {        Message msg = mMessages;        if (msg != null) {            if (now >= msg.when) {                mMessages = msg.next;                if (Config.LOGV) Log.v(                    "MessageQueue", "Returning message: " + msg);                return msg;            }        }        return null;    }

?

?

Handler

这样你的线程就具有了消息处理机制了,在Handler中进行消息处理。Activity是一个UI线程(主线程),Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper)。Handler的作用是把消息加入特定的消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建。?一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在主线程中处理了。因为主线程一般负责界面的更新操作,所以这种方式可以很好的实现Android界面更新。那么另外一个线程怎样把消息放入主线程的消息队列呢?是通过Handle对象,只要Handler对象以主线程的Looper创建,那么调用 HandlersendMessage,将会把消息放入主线程的消息队列。并且将会在主线程中调用该handlerhandleMessage方法来处理消息。

?

Message

获取消息:直接通过Messageobtain方法获取一个Message对象或者直接new一个Message对象。源码如下

public?final?Message?obtainMessage(int?what,?int?arg1,?int?arg2,?Object?obj){????

?????return?Message.obtain(this,?what,?arg1,?arg2,?obj);????

?}?? ?

?

Message.obtain函数:从Message Pool中取出一个Message,如果Message Pool中已经没有Message可取则新建一个Message返回。

Message Pool:大小为10

清理MessageLooper里面的loop函数指把处理过的Message放到MessagePool里面去,如果里面已经超过最大值10个,则丢弃这个Message对象。

发送消息:通过MessageQueueenqueueMessageMessage对象放到MessageQueue的接收消息队列中,源码如下:

?

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;      }     

?

?

线程如何处理MessageQueue中接收的消息:在Looperloop函数中循环取出MessageQueue的接收消息队列中的消息,然后调用 HanderdispatchMessage函数对消息进行处理,源码如下:

?

?

public void dispatchMessage(Message msg) {           if (msg.callback != null) {               handleCallback(msg);         } else {             if (mCallback != null) {                  if (mCallback.handleMessage(msg)) {                      return;                }              }              handleMessage(msg);          }      }     

?

?

参考:

http://www.android123.com.cn/androidkaifa/422.html

http://dev.10086.cn/cmdn/wiki/index.php?edition-view-2600-1.html

http://hi.baidu.com/dragon_eros/blog/item/6eaf600cb4e22f28e824881c.html

1 楼 nick714 2011-07-13  
jiang de hen tou che a ,haha,wo shi wang bin
2 楼 zhoujianghai 2011-07-13  
nick714 写道
jiang de hen tou che a ,haha,wo shi wang bin

ni de shu ru fa ye huai le? 
3 楼 xiaowangzaixian 2011-08-25  
good   
  相关解决方案