首页 > 程序开发 > 移动开发 > Android >

Android 消息处理机制2(从源码分析)

2016-09-12

下面介绍 “猪脚光环的” : Handler 、Message 、MessageQueue Looper。并以Java 程序模拟安卓的消息处理机制,Handler 在前面已经介绍过了,从创建Handler 实例顺藤摸瓜…

下面介绍 “猪脚光环的” : Handler 、Message 、MessageQueue Looper。并以Java 程序模拟安卓的消息处理机制

Handler 在前面已经介绍过了,从创建Handler 实例顺藤摸瓜…

Handler 原理

Handler 封装了消息的发送 (— > 发给谁) 【默认指向自己】 Handler 的依赖对象 Looper 意为:轮询 . 其内部包含了一个消息队列也就是 MessageQueue ,MessageQueue 封装了消息( Message)的载体 所有Handler 发送的信息都走向这个消息队列

两大用途

There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

...
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(); //进行关联
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = null;
    }

    ...

由源码得出:

Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable),postAtTime(Runnable,long),postDelayed(Runnable,long).
sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int), sendMessage(Message).sendMessageAtTime(Message,long).sendMessageDelayed(Message,long)。
  从上面的各种方法可以看出,不管是post还是sendMessage都具有多种方法,它们可以设定Runnable对象和Message对象被入队到消息队列中,是立即执行还是延迟执行。

Looper 原理

本质是一个死循环 不断地从 MessageQueue 中取出数据,有消息就取出,没消息就阻塞。

Looper中重要的方法:

static void loop()
Run the message queue in this thread.

为什么Handler 内部要与 Looper 进行关联?

不关联Handler 如何向MessageQueue 发送Message呢

总的来说: Handler 负责发送消息,Looper 负责接收消息并把消息回传给 Handler , 而 MessageQueue 是就是存储 Message 的容器

Framework 源码简析

UI 线程 ActivityThread 创建 Looper Message

这里写图片描述

这里写图片描述

这里写图片描述

new LoZ喎"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcGVyKCk7ILrz1/bBy8TH0Kmy2df3xNijvzwvcD4NCjxwPjxpbWcgYWx0PQ=="这里写图片描述" src="http://www.2cto.com/uploadfile/Collfiles/20160912/201609120928371073.png" title="\" />

如何取出 当前线程关联的 Looper 对象?

public static Looper myLooper() {
        return sThreadLocal.get();
}

Handler 发送消息到 MessageQueue (消息入列)

这里写图片描述

Handler取出 当前线程关联的 Looper 对象 是为了Looper 中MessageQueue 对象进行发送消息Message

Tips:对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。  

Java 程序实现

下面代码由 Framework 源码拷贝出来进行分析,每一位安卓工程师都应该拥有一份 Framework 源码,以便了解android.

ActivityThread (程序入口)

public class ActivityThread {

    public static void main(String[] args) {
        //初始化主线程的 Looper 对象
        Looper.prepareMainLooper();
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                System.out.println("接收到 what = " + msg.what);
                System.out.println("Thread " + Thread.currentThread().getName());
            }
        };
        handler.sendEmptyMessage(1);
        handler.sendEmptyMessage(2);
        new Thread(new Runnable() {
            @Override
            public void run() {
                handler.sendEmptyMessage(1001);
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //子线程 通过Handler 发送消息到主线程的消息队列, 主线程处理该消息
                handler.sendEmptyMessage(1001);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                handler.sendEmptyMessage(1000);
                handler.sendEmptyMessage(1000);
                handler.sendEmptyMessage(1000);
                handler.sendEmptyMessage(1000);
                handler.sendEmptyMessage(1000);

                //初始化 Looper
                Looper.prepare();
                final Handler handler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        //子线程
                        System.out.println("接收到 what = " + msg.what);
                        System.out.println("Thread " + Thread.currentThread().getName());
                    }
                };

                handler.sendEmptyMessage(999);
                handler.sendEmptyMessage(9999);
                //轮询
                Looper.loop();
            }
        }).start();
        //轮询
        Looper.loop();
    }
}

Handler 代码

package android.os;

/**
 * Created by system on 16/9/6.
 * 
* 处理和分发消息 * */ public class Handler { final MessageQueue mQueue; final Looper mLooper; public Handler() { mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; } public void handleMessage(Message msg) { } /** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg != null) { handleMessage(msg); } } public final boolean sendEmptyMessage(int what) { Message msg = new Message(); msg.what = what; MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); System.out.println(e.getMessage()); return false; } msg.target = this; return queue.enqueueMessage(msg); } }

Looper

package android.os;

/**
 * Created by system on 16/9/6.
 *
 *
 * 每开启一条线程都应为之创建一个与该线程绑定 Looper 对象 ,以及 MessageQueue 队列
 */
public class Looper {

    static final ThreadLocal sThreadLocal = new ThreadLocal();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
    final Thread mThread;

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

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

    public static void prepareMainLooper() {
        prepare();
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    public static Looper myLooper() {
        return sThreadLocal.get();
    }

    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;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            //分发消息
            msg.target.dispatchMessage(msg);


        }
    }
}

Message

package android.os;

/**
 * Created by system on 16/9/6.
 *  消息
 *  由MessageQueue统一列队,终由Handler处理。
 */
public class Message {

    public int what;

    /*package*/ Handler target;

    /*package*/ Runnable callback;

    // sometimes we store linked lists of these things
    /*package*/ Message next;


}

MessageQueue

package android.os;

/**
 * Created by system on 16/9/6.
 *
 * 消息队列,用来存放Handler发送过来的消息(Message),并按照FIFO规则执行
 * note:(将Message以链表的方式串联起来的,等待Looper的轮询)
 */
public class MessageQueue {
    Message mMessages;// 当前消息
    private static final Object lock = new Object();

    /**
     * 出列 FO (即取出队头的消息)
     * @return Message
     */
    Message next() {
        //没有消息时 阻塞
        for (; ; ) {
            synchronized (this) {
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null);
                }
                if (msg != null) {

                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next; //成为队头
                    }
                    msg.next = null; //remove
                    return msg;
                }

            }
        }
    }

    /**
     * 消息入列  FIFO
     * @param msg
     * @return
     */
    boolean enqueueMessage(Message msg) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        synchronized (this) {

            Message p = mMessages;

            if (p == null) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;

            } else {
                Message prev;
                for (; ; ) {
                    prev = p;
                    p = p.next;
                    if (p == null) {
                        break;
                    }

                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg; //成为链尾
            }

        }
        return true;
    }
}

运行效果图:
这里写图片描述

相关文章
最新文章
热点推荐