Handler Looper Message MessageQueue的理解

最近又好好看了下线程相关的东西,记录下,方便以后学习.
首先有个主要概念.
每个Thread都会对应一个自己的Looper.
每个Looper里面都有一个自己的MessageQueue.
每个MessageQueue可以有多个Message.
每个Message对应一个Handler处理.
线程的创建有主线程(main thread)和一般线程(Thread)
首先是主线程,一般应用启动创建第一个activity的时候回创建主线程,同时还有两个Binder线程,Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法(源码2.3.3):
为实在静态的main()方法
中,所以new了一下.

 public static final void main(String[] args) {
        // other codes...

        // 创建主线程循环
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        // other codes...

        // 进入当前线程(此时是主线程)消息循环
        Looper.loop();

        // other codes...

        thread.detach();
        // other codes...
    }
下面按照源码解释下,主线程中先是调用Looper.prepareMainLooper();创建一个Looper.可以通过Looper.getMainLooper()
方法获取主线程的Looper.一般线程调用Looper.prepare()创建Looper;
通过,Looper.myLooper()获取Looper.

分析Looper.prepareMainLooper();先看下源码

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
按顺序分析,进入prepare(false)方法中,false是该线程不可退出(因为是主线程),true是可退出.

一般线程 就是prepare(true),下面会用到.

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.在Looper类中,有以下几个变量
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    final MessageQueue mQueue;
    final Thread mThread;
可以看到sThreadLocal 是一个ThreadLocal类的对象,类ThreadLocal
为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地
改变自己的副本,而不会影响其它线程所对应的副本。
主要用set()和get()两个方法
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }
在prepare()方法中,通过sThreadLocal.set(new Looper(quitAllowed));把一个Looper对象放入,因一个thread还有唯一looper,
也就相当于把当前线程放入sThreadLocal中.

sThreadLocal中.顺便看下Looper的构造方法

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
构造方法中可以看出,创建了一个消息队列mQueue ,同时绑定了当前线程.即解释了,一个线程对应一个Looper,一个Looper有唯一的一个消息队列.
这些都是在Looper.prepareMainLooper()中完成.接着看下一般线程的Looper.prepare();
public static void prepare() {
        prepare(true);
    }
哎呀,好简单,直接调用了private static void prepare(boolean quitAllowed) 方法,在prepareMainLooper();中也调用了这个方法,
传入的是false,之前说了,false表示不可退出,true一般线程可退出.其它和上面一样.
接下里看下Handler,首先明确Handler的作用

1,将Message压入消息队列
2,分发处理Message.
先看下压入消息队列过程,在分发Message之前,我们先看下,handler是如何和Message关联的.先看下handler的构造方法先看下常用的new Handler()的无参构造方法.

public Handler() {
        this(null, false);
    }
 //这个方法调用了下面这个方法
 public Handler(Callback callback, boolean async) {
        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());
            }
        }
        //获取looper对象
        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 = callback;
        mAsynchronous = async;
    }

由此可以看出,显示通过Looper.myLooper();获取当前Thread的looper,looper抛出异常,不为空
在通过looper获取当前的消息队列mQueue = mLooper.mQueue;这样,handler就和Thread,Looper和MessageQueue关联在一起了.
还有一种handler = new Handler(Looper looper),可传入,Looper.getMainLooper()或者Looper.getLooper();

 public Handler(Looper looper) {
        this(looper, null, false);
    }
 //调用
 public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

和上面一样,获取Looper,然后取得对应MessageQueue.
接下来看下handler如何分发消息,一般有下面几个方法

send方法
 1. public final boolean sendMessage(Message msg)
 2. public final boolean sendEmptyMessage(int what)
 3. public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
 4. public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
 5. public final boolean sendMessageDelayed(Message msg, long delayMillis)
 6. public boolean sendMessageAtTime(Message msg, long uptimeMillis) 
 7. public final boolean sendMessageAtFrontOfQueue(Message msg)
post方法
 1. public final boolean post(Runnable r)
 2. public final boolean postAtTime(Runnable r, long uptimeMillis)
 3. public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
 4. public final boolean postDelayed(Runnable r, long delayMillis)
 5. public final boolean postAtFrontOfQueue(Runnable r)
 6. public final boolean runWithScissors(final Runnable r, long timeout)

从handler.post(Runnable r)看

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
private static Message getPostMessage(Runnable r) {
        //这样获取Message对象效率更高而且不创建对象节省内存
        Message m = Message.obtain();
        //这个处理消息时就先判断了是否为空
        m.callback = r;
        return m;
    }

从上可以看出,runnable最后也是转化为了Message来处理的.然后调用sendMessageDelayed(getPostMessage(r), 0)方法.而

public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }
 public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    ...

这些方法最终都是调用的send方法,下面先看下sendMessage(Message msg);

public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
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);
    }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

代码都容易懂,最终通过queue.enqueueMessage()方法将msg压入消息队列.msg.target = this;这个可以记着,将当前handler传给msg.target,后面还要用到,以免疑惑.
下面是queue.enqueueMessage(msg, uptimeMillis)的源码,有兴趣可以看下

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

接下来,msg放入了消息队列,handler怎样处理,这就要通过Looper了,相当于电动机,不断将消息取出交给handler处理,下面看下Looper.loop()方法,可以看下注释

public static void loop() {
        //获取当前looper
        final Looper me = myLooper();
        //为空报运行时异常,没有looper不能处理消息
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //根据looper对象,获取对应的消息队列
        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 (;;) {
            //获取msg
            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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            //传递Message信息,上面提到的msg.target,这个就是Handler对象,这里调用
            //Handler中的方法分发信息
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

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

由上可以看出调用了handler.dispatchMessage(msg)方法分发处理消息.看源码

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
private static void handleCallback(Message message) {
        message.callback.run();
    }
public interface Callback {
        public boolean handleMessage(Message msg);
    }
public void handleMessage(Message msg) {
    }

上面是源码中处理过程,我们来看下三种处理方案

  1. 在前面post(Runnable r)中返回时调用的getPostMessage(Runnable r)中将Runnable对象赋值给了m.callback,即m.callback = r这一句;接着分析先是判断msg.callback是否为空,为空交给下面处理.不为空交给handleCallback(Message message)方法处理调用message.callback.run()方法,即是我们常用的handler.post(Runnable r)方法,runnable对象就是message.callback.
  2. message.callback为空,然后然后判断mCallback 是否为空,为空交给下面处理,不为空由mCallback.handleMessage(msg)方法处理信息.如下
handler = new Handler(new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                return false;
            }
        });
3.交给handleMessage(msg);方法处理,这个就是我们常用的,一般我们重写该方法处理msg如下
handler = new Handler(getMainLooper())
        {
            @Override
            public void handleMessage(Message msg)
            {
                super.handleMessage(msg);
            }
        };

除了这些我们还可以取消消息,可以根据what调用public final void removeMessages(int what)方法,也可以通过public final void removeCallbacksAndMessages(Object token)移除所有的消息.一般为了防止内存泄漏,在销毁activity时,可调用,移除所有message.

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值