阅读更多

 

作用: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,将会把消息放入主线程的消息队列。并且将会在主线程中调用该handler handleMessage方法来处理消息。

 

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. Android(安卓)消息机制:Handler、Looper、Message源码 详细版解析
  2. Handler 消息传递机制
  3. kotlin优雅实现AIDL
  4. andorid ANR keyDispatchingTimedOut的原因和解决之道
  5. 备战面试旺季:2019年Android面试题整理(组件+View+线程+面经)
  6. Android(安卓)任务、进程和线程
  7. Android(安卓)AsyncTask与handler
  8. 见证Android消息推送时刻(源码及详解)
  9. Android使用mqtt协议实现消息收发

随机推荐

  1. Android的消息机制
  2. Android(安卓)编程下 Touch 事件的分发和
  3. Android(安卓)中文 API (30) ―― Compound
  4. Android分享界面制作(底部滑出动画)
  5. Android的System Server
  6. android编写访问http的代码
  7. ArcGIS for Android
  8. android:layout_weight的真实含义
  9. Android-基本控件(SeekBar 可拖动 滚动条
  10. android中getCacheDir(),getFilesDir(),get