我是靠谱客的博主 忐忑啤酒,最近开发中收集的这篇文章主要介绍android基础知识02——线程安全3:Message,MessageQueue,Handler,Looper,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        

        android的UI操作不是线程安全的,同时也只有主线程才能够操作UI,同时主线程对于UI操作有一定的时间限制(最长5秒)。为了能够做一些比较耗时的操作(比如下载、打开大文件等),android提供了一些列机制。《android基础知识02——线程安全》系列文章就是参考了网上许多网友的文章后,整理出来的一个系列,介绍了主要的方法。分别如下:

         android基础知识02——线程安全1:定义及例子

        android基础知识02——线程安全2:handler、message、runnable

        android基础知识02——线程安全3:Message,MessageQueue,Handler,Looper

        android基础知识02——线程安全4:HandlerThread

        android基础知识02——线程安全5: AsyncTask


        在上文例子中,用到了消息队列,这里就不得不提与之相关的Message,MessageQueue,Handler,Looper。

        线程,MessageQueue,Handler,Looper之 间的关系可以通过一个图来展示:



1、Handler

 --用来处理消息和线程

--每个Handler可以执行一个线程对象(Runnable实现)也可以发送和处理消息
>>post(Runnable)
>>postAtTime(Runnable,long)
>>postDelayed(Runnable,long)
>>sendEmptyMessage(int)
>>sendMessageAtTime(Message,long)
>>sendMessageDelayed(Message,long)
>>handleMessage(Message)
        通过Handler你可以发布或者处理一个消息或者是一个Runnable的实例。每个Handler都会与唯一的一个线程以及该线程的消息队列管理。当你创建一个新的Handler时候,默认情况下,它将关联到创建它的这个线程和该线程的消息队列。也就是说,如果你通过Handler发布消息的话,消息将只会发送到与它关联的这个消息队列,当然也只能处理该消息队列中的消息。
主要的方法有:
1)   public final boolean sendMessage(Message msg)
把消息放入该Handler所 关联的消息队列,放置在所有当前时间前未被处理的消息后。
2)   public void handleMessage(Message msg)
关联该消息队列的线 程将通过调用Handler的handleMessage方 法来接收和处理消息,通常需要子类化Handler来 实现handleMessage。
removeMessages(0)来清除消息队列 。

        这个是我从网络上找到的介绍,如果你看到handler的源代码,则其介绍这样的:

* A Handler allows you to send and process {@link Message} and Runnable
 * objects associated with a thread's {@link MessageQueue}.  Each Handler
 * instance is associated with a single thread and that thread's message
 * queue.  When you create a new Handler, it is bound to the thread /
 * message queue of the thread that is creating it -- from that point on,
 * it will deliver messages and runnables to that message queue and execute
 * them as they come out of the message queue.
 * 
 * <p>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 class Handler {
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
public interface Callback {
public boolean handleMessage(Message msg);
}
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
IMessenger mMessenger;
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
public Handler() {
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());
}
}
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;
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
public Handler() {
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());
}
}
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;
}
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;
}
        从源码分析可以看出:
        1)handler在无参数的构造方法中调用Looper.myLooper()方法,里面就是从当前线程里面获取一个Looper对象,如果没有则创建.这样对Looper就进行初始化,初始化Looper的同时一并初始化MessageQueue,并且从中得到looper的MessageQueue .可以看出Handler就是Looper和MessageQueue的管理者和调度者.

        2)其中最重要的是:sendMessageAtTime(Message msg, long uptimeMillis)这个方法,当你往Handler中发送Message消息的时候,从代码看出他自己并不去处理Message ,而是交给了MessageQueue.由以下从这段代码来处理:

       3)runnable对象在处理时,是创建一个新的Message并将其mCallback设置为该runnable对象,并将该Message插入到MessageQueue。

        4)handler的功能包括两部分:处理消息(执行Message的内容)、转发消息,其中主要由handleMessage和dispatchMessage这两个函数处理;

        5)handler中不管是send message还是post runnable都是将其加入到MessageQueue 。

        queue.enqueueMessage(msg, uptimeMillis), 其具体实现要看下面的对。

2、Message

frameworksbasecorejavaandroidOsMessage.java

--定义一个信息对象,该信息对象可以发送给Handler对象来处理。
--可以通过Message.obtain()或者Handler.obtainMessage()方法来实例化
        Message是线程之间传递信息的载体,包含了对消息的描述和任意的数据对象。Message中包含了两个额外的 int字段和一个object字段,这样在大部分情况下,使用者就不需要再做内存分配工作了。虽然Message的构造函数是public的,但是最好是使用Message.obtain( )或Handler.obtainMessage( )函数来获取Message对象,因为Message的实现中包含了回收再利用的机制,可以提供效率。

 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.  

public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
long when;
Bundle data;
Handler target;
Runnable callback;
Message next;
private static Object mPoolSync = new Object();
private static Message mPool;
private static int mPoolSize = 0;
private static final int MAX_POOL_SIZE = 10;
When: 向Handler发送Message生成的时间
Data: 在Bundler 对象上绑定要线程中传递的数据
Next: 当前Message 对一下个Message 的引用
Handler: 处理当前Message 的Handler对象.
mPool: 通过字面理解可能叫他Message池,但是通过分析应该叫有下一个Message引用的Message链更加适合.
其中Message.obtain(),通过源码分析就是获取断掉Message链关系的第一个Message.

       对于源码的解读,可以明确两点:

        1)Message.obtain()是通过从全局Message pool中读取一个Message,回收的时候也是将该Message 放入到pool中。

        2)Message中实现了Parcelable接口。

3、MessageQueue

--维护一个消息列表,该列表中的消息通过Looper对象来分发。
--调用Looper.myQueue()方法可以获得一个MessageQueue对象
        Message Queue是一个消息队列,用来存放通过Handler发布的消息。消息队列通常附属于某一个创建它的线程,可以通过Looper.myQueue()得 到当前线程的消息队列。Android在 第一启动程序时会默认会为UI thread创建一个关联的消息队列,用来管理程序的一些上层组件,activities,broadcast receivers 等等。你可以在自己的子线程中创建Handler与UI thread通讯。 

/**

 * Low-level class holding the list of messages to be dispatched by a
 * {@link Looper}.  Messages are not added directly to a MessageQueue,
 * but rather through {@link Handler} objects associated with the Looper.
 * <p>You can retrieve the MessageQueue for the current thread with
 * {@link Looper#myQueue() Looper.myQueue()}.
 */

public class MessageQueue {
Message mMessages;
private final ArrayList mIdleHandlers = new ArrayList();
private boolean mQuiting = false;
boolean mQuitAllowed = true;
public static interface IdleHandler {
boolean queueIdle();
}
public final void addIdleHandler(IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
final boolean enqueueMessage(Message msg, long when) {
if (msg.when != 0) {
throw new AndroidRuntimeException(msg
+ " This message is already in use.");
}
if (msg.target == null && !mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit");
}
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
} else if (msg.target == null) {
mQuiting = true;
}
msg.when = when;
//Log.d("MessageQueue", "Enqueing: " + msg);
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
this.notify();
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}
return true;
}
mMessages: 为当前序列的第一个Message, 通过源码分析 MessageQueue并不是对许多Message 之间的关系维护,这样也许可以省去很多事把,而Message 之间的关系
则统统丢给了Message自己去维护,这个可以从对Message源码分析可以理解.
mIdleHandler: 保存的是一系列的handler的集合.
其中final boolean enqueueMessage(Message msg, long when),
这个方法就是上面提到Handler 处理消息时调用到的方法,对她理解了就显的很重要了,其按延迟时间长短,将延迟时间短的放在前面,功能代码如下:
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
this.notify();
} else {
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
        当向MessageQueue中添加消息的时候,判断当前的Message(mMessage)是否为空,
        如果为空或者when=0或者when<p.when: 则把要添加的Message(msg)赋给当前的Message(mMessage),并且将msg.next属性设为空,

       如果不为空: 则循环把当前的Message(mMessage)的下一个Message(next)进行遍历,用prev记住当前的message,直到找到prev的下一个Message为空的时候就退出循环,最后将msg接到prev的屁股后面,即这段代码: prev.next = msg; 

        当然,需要注意到,在其中定义了一个IdleHandler接口,该接口只有一个方法申明:boolean queueIdle()。MessageQueue类中addIdleHandler(IdleHandler handler)函数用于添加队列为空时的IdleHandler。当队列为空时,需要一一通知这些IdleHandler。

4、Looper

--该类用来为一个线程维护一个消息队列
--默认的线程是没有和一个Looper实例关联的,需要在线程中使用Loop.prepare();关联一个线程,使用Looper.loop()处理消息直到结束。

        Looper扮演着一个Handler和 消息队列之间通讯桥梁的角色。程序组件首先通过Handler把 消息传递给Looper,Looper把 消息放入队列。Looper也 把消息队列里的消息广播给所有的Handler,Handler接 受到消息后调用handleMessage进 行处理。
1)   可以通过Looper类 的静态方法Looper.myLooper得 到当前线程的Looper实 例,如果当前线程未关联一个Looper实 例,该方法将返回空。
2)   可以通过静态方法Looper. getMainLooper方法得到主线程的Looper实 例。

/**
* Class used to run a message loop for a thread.
Threads by default do
* not have a message loop associated with them; to create one, call
* {@link #prepare} in the thread that is to run the loop, and then
* {@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
*
class LooperThread extends Thread {
*
public Handler mHandler;
*
public void run() {
*
Looper.prepare();
*
mHandler = new Handler() {
*
public void handleMessage(Message msg) {
*
// process incoming messages here
*
}
*
};
*
*
Looper.loop();
*
}
*
}</pre>
*/

public class Looper {
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
// sThreadLocal.get() will return null unless you've called prepare().
private static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
volatile boolean mRun;
Thread mThread;
private Printer mLogging = null;
private static Looper mMainLooper = null;
 /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
/** Initialize the current thread as a looper, marking it as an application's main 
     *  looper. The main looper for your application is created by the Android environment,
     *  so you should never need to call this function yourself.
     * {@link #prepare()}
     */
     
    public static final void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        if (Process.supportsProcesses()) {
            myLooper().mQueue.mQuitAllowed = false;
        }
    }
    private synchronized static void setMainLooper(Looper looper) {
        mMainLooper = looper;
    }
    
    /** Returns the application's main looper, which lives in the main thread of the application.
     */
    public synchronized static final Looper getMainLooper() {
        return mMainLooper;
    }
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
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();
}
}
}
/**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }
        从源码可以看出Looper 封装的信息:
       Looper实质上是对当前线程, ThreadLocal,MessageQueue的封装,也就是负责在多线程之间传递消息的一个循环器.

       当你往Handler中添加消息的时候则,里面这个方法: public static final void loop()死循环的方法就会被系统调用,之后的功能代码是: 
msg.target.dispatchMessage(msg),则从MessageQueue中得到一个Message(msg),之后调用Handler的dispatchMessage(msg),这个方法内部实际调用的就是 Handler.handleMessage(msg)方法,这个就是我们在activity要重写的方法,所以我们就能够得到其他子线程传递的Message了.

最后

以上就是忐忑啤酒为你收集整理的android基础知识02——线程安全3:Message,MessageQueue,Handler,Looper的全部内容,希望文章能够帮你解决android基础知识02——线程安全3:Message,MessageQueue,Handler,Looper所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部