博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android分析之消息处理
阅读量:5954 次
发布时间:2019-06-19

本文共 8412 字,大约阅读时间需要 28 分钟。

前序:每个APP对应一个进程,该进程内有一个ActivityThread的线程,称为主线程(即UI主线程),此外,还有其他线程,这个再论。

 

android的消息系统分析。

  1. 每个Thread只对应一个Looper
  2. 每个Looper只对应一个MessageQueue
  3. 每个MessageQueue中有N个Message
  4. 每个Message中最多指定一个Handler来处理事件
  5. 一个Thread可以对应多个Handler

Looper负责从消息队列中(MessageQueue)取出消息(Message/Runnable),交给Handler来处理。

 

Message:

public final class Message implements Parcelable {     public int what;//每个Message可以指定一个Handler,由于可以存在多个Handler,用what来标识具体的Handler    public int arg1;     public int arg2;    public Object obj;    public Messenger replyTo;    /*package*/ static final int FLAG_IN_USE = 1 << 0;    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;    /*package*/ int flags;    /*package*/ long when;        /*package*/ Bundle data;        /*package*/ Handler target;//指定由哪个Handler来处理本Message        /*package*/ Runnable callback;           /*package*/ Message next;//消息链    private static final Object sPoolSync = new Object();    private static Message sPool;//消息链表的头,注意是static    private static int sPoolSize = 0;    private static final int MAX_POOL_SIZE = 50; ...... }

 

MessageQueue实际上是对Message的一种操作的封装,真正的消息队列是以sPool为首的消息链表:

public class MessageQueue {    // True if the message queue can be quit.    private final boolean mQuitAllowed;    @SuppressWarnings("unused")    private int mPtr; // used by native code    Message mMessages;//消息...    private final ArrayList
mIdleHandlers = new ArrayList
(); private IdleHandler[] mPendingIdleHandlers; private boolean mQuiting; // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. private boolean mBlocked; // The next barrier token. // Barriers are indicated by messages with a null target whose arg1 field carries the token. private int mNextBarrierToken; //调用Native函数做真正的处理 private native void nativeInit(); private native void nativeDestroy(); private native void nativePollOnce(int ptr, int timeoutMillis); private native void nativeWake(int ptr); ...... }

 

  Looper:

public class Looper {    private static final String TAG = "Looper";    static final ThreadLocal
sThreadLocal = new ThreadLocal
();//与线程相关的模板类 private static Looper sMainLooper; //static类型,只有一个 final MessageQueue mQueue;//Looper持有的MessageQueue final Thread mThread; volatile boolean mRun; private Printer mLogging; ...... }

  

Handler:

public class Handler{//真正对处理Message的类:包括处理Message和将消息压到MessageQueue队列里    final MessageQueue mQueue;    final Looper mLooper;    final Callback mCallback;    IMessenger mMessenger;...}

  

Looper的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;        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);//调用消息指定的接收者Handler来处理它            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.recycle();//丢弃消息,循环再利用        }    }

  Handler取消息,每次从sPool(Message里的static Message类型)取出一个Message,其调用的是static方法:

public static Message obtain(Handler h, int what, Object obj) {        Message m = obtain();        m.target = h;        m.what = what;        m.obj = obj;        return m;    }

  Handler将消息压入消息队列:

public boolean sendMessageAtTime(Message msg, long uptimeMillis)    {        boolean sent = false;        MessageQueue queue = mQueue;        if (queue != null) {            msg.target = this;            sent = queue.enqueueMessage(msg, uptimeMillis);//调用MessageQueue的方法执行压入操作        }        else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;    }

  小结:Handler取消息是直接取(从sPool里),将消息压入MessageQueue是调用MessageQueue的方法。

----------------------------------------------分割线----------------------------------------------------------------------------

下面分析这些对象都是在什么时候创建的。

Looper是什么时候创建的?

每个线程都只有一个Looper对象。

1.普通线程(非主线程)

一个典型的自己创建的线程使用Looper如:

class LooperThread extends Thread{    public Handler mHandler;    public void run(){        Looper.prepare();        mHandler= new Handler(){                public void handleMessage(Message msg){                    //处理消息                }        };        Looper.loop();//进入消息循环    }}

  那么Looper是在什么时候创建的呢?看Looper.prepare()方法:执行完这个方法,就得到了一个本线程独有的Looper。

static final ThreadLocal
sThreadLocal = new ThreadLocal
();//这是一个与线程先关的模板类 private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) {//若调用者所在宿主线程已经有Looper,则抛出异常 throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));//Java中的线程局部存储,即不同线 }//程都通过sThreadLocal得到自己的不同的Looper对象引用
private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);//创建Looper要处理的消息队列        mRun = true;        mThread = Thread.currentThread();//得到当前线程    }

  

  那么Handler是如何与Looper关联起来的呢?看Handler的构造方法:

public Handler() {        if (FIND_POTENTIAL_LEAKS) {            final Class
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();//通过线程局部存储,获得本线程的Looper if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null; }
public static Looper myLooper() {//获取与本线程相关的Looper        return sThreadLocal.get();    }

  

  小结:每个线程都通过sThreadLocal<Looper>来创建一个Looper(进而创建一个MessageQueue),再创建一个Handler(通过sThreadLocal),从而将Handler与Looper“绑定”在一起,形成一个完整的消息循环系统。

 

2.主线程ActivityThread

主线程是什么时候创建Looper的?在ActivityThread.java的main方法里有:

public static void main(String[] args) {        SamplingProfilerIntegration.start();        CloseGuard.setEnabled(false);        Process.setArgV0("
"); Looper.prepareMainLooper();//也是sThreadLocal.set(new Looper(quitAllowed))来创建一个线程所属的Looper,并通过sThreadLocal.get()将Looper赋给sMainLooper(private static Looper sMainLooper),sMainLooper的作用就是,其他线程可以获取到主线程的Looper(因为sMainLooper是static,在主线程中赋值的)。 if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }

  

Looper.loop()是一个static的方法,作为消息循环处理器,不断的取消息,分发消息。

 

转载于:https://www.cnblogs.com/littlefishxu/p/3985130.html

你可能感兴趣的文章
协同过滤及大数据处理
查看>>
Java8 本地DateTime API
查看>>
jQuery 增加 删除 修改select option
查看>>
[原][osgearth]osgearthviewer读取earth文件,代码解析(earth文件读取的一帧)
查看>>
springboot 常用插件
查看>>
一个基于特征向量的近似网页去重算法——term用SVM人工提取训练,基于term的特征向量,倒排索引查询相似文档,同时利用cos计算相似度...
查看>>
[转]Newtonsoft.Json高级用法
查看>>
Spring+SpringMVC+MyBatis+easyUI整合基础篇(一)项目简述及技术选型介绍
查看>>
DFI、DPI技术
查看>>
hibernate 执行存储过程 方法
查看>>
RapidIOIP核的验证方法研究_王玉欢
查看>>
崩溃日志的实例
查看>>
base64是啥原理
查看>>
实战 Windows Server 2012 群集共享卷
查看>>
CSS 元素超出部分滚动, 并隐藏滚动条
查看>>
React中那些纠结你的地方(一)
查看>>
Docker入门安装教程
查看>>
PhoneGap极光推送 cordova消息推送
查看>>
Subarray Sum Equals K
查看>>
preventDefault, stopPropagation, stopImmediatePropagation 三者的区别
查看>>