Android Handler消息处理机制 一些事一些情

来源:互联网 发布:阿里云 杰出 科学家 编辑:程序博客网 时间:2024/06/03 13:18

Android消息处理机制(Handler、Looper、MessageQueue与Message)

1、Message : 消息
2、MessageQueue : 消息队列
3、Looper:消息循环,用于循环取出消息进行处理(维护消息队列)
4、Handler :Looper在MessageQueue中取出消息后对消息进行处理


我们都知道Android 的入口主程序是 ActivityThread此类的main方法,它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数)。

public final class ActivityThread {..................... final Looper mLooper = Looper.myLooper();.....................public static void main(String[] args) {    ..........................    Looper.prepareMainLooper();    //这里是调用Looper的循环器,不断取出消息并用handler分发    Looper.loop();    .......................    }}

这就是我们入口主程序了,是不是看到了Looper,这就是对了,android消息机制默认就是主线程,不需要我们手动来启动一个Looper来建立一个主线程来更新UI,而在子线程中,我们则需要手动来开启一个Looper来开启消息循环和停止消息循环。好,我们一步步来,是不是看到了一个全局的mLooper ,通过 Looper.myLooper()的静态方法来获取一个Looper对象,源码查看:

/**Return the Looper object associated with the current thread.  Returns null if the calling thread is not associated with a Looper. */返回当前线程的Looper对象,如果返回null,则说明当前线程没有相关的Looper对象。    //这个myLoope()方法,主要是获取存储在ThreadLocal的Looper对象    public static Looper myLooper() {        return sThreadLocal.get();    }

再看看 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();        }    }该方法是把主线程和消息序列放进Looper里面,同时把Looper放到ThreadLocal中

下面讲一下Looper类的重要的几个方法:
1、prepare()
在prepare()方法中,判断了一下为不为Null,如果当前的ThreadLocal里面有值,就会抛出异常,ThreadLocal作用是保存当前线程的变量,在这里是保存Looper对象,这说明了该方法不能调用2次,并且一个线程中只有一个Looper对象。并且实例了一个MessageQueue(消息队列)。

public static final void prepare() {          //保证了Looper的唯一性        if (sThreadLocal.get() != null) {              throw new RuntimeException("Only one Looper may be created per thread");          }          //该方法是实例Looper对象,在构造方法中实例了消息队列        sThreadLocal.set(new Looper(true));  }private Looper(boolean quitAllowed) {          mQueue = new MessageQueue(quitAllowed);          mRun = true;          mThread = Thread.currentThread();  }  

2、loop()方法,稍微有点长……

    //这个myLoope()方法,主要是获取存储在ThreadLocal的Looper对象public static Looper myLooper() {        return sThreadLocal.get(); } public static void loop() {//可以看出myLooper该方法就是获取保存在ThreadLocal的Looper对象//因为可以联想到什么,我们是在prepare()方法实例Looper,并且保存到ThreadLocal中,因为,prepare()方法必须执行于loop()方法之前,否则抛出异常!        final Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }//looper实例中的mQueue(消息队列),在实例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 (;;) {            //在一个无限循环中不断取出消息            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);            }//取出消息的target(就是handler),执行分发消息的处理操作,//因为dispatchMessage()这个方法是Handler中的,通过Message中的Handler引用来调用该方法来处理消息,在Message中的Hnalder的引用名字就是target,哈哈哈......            msg.target.dispatchMessage(msg);            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);            }            //把Message对象的标记,信息置为空            msg.recycleUnchecked();        }    }

好好,既然msg拿到了,也交到了Handler的手中,那么来看看Handler是怎样处理的。

public class Handler {   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实例,就是上面提到的。        //主要是myLooper这个方法都是获取当前的Looper实例。        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");            }/**获取了这个Looper实例中保存的MessageQueue(消息队列),上面创建Looper的时候就已经提到了,实例Looper的时候,会构建一个MessageQueue,而在消息队列中获取了Message,又通过了hanler的dispatchMessage()方法,把这个消息发送过去了,下面我们来看看dispatchMessage()这个方法,这样就handler、Looper、MessageQueue就有了关联。*/        mQueue = mLooper.mQueue;//获取上面保存的消息队列        mCallback = callback;//这个就消息的回调,下面有源码        mAsynchronous = async;  }    public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        //这里把Handler的mQueue指向Looper的mQueue        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;    }    private static final boolean FIND_POTENTIAL_LEAKS = false;    private static final String TAG = "Handler";    public interface Callback {        public boolean handleMessage(Message msg);    }    public void handleMessage(Message msg) {    }     public void dispatchMessage(Message msg) {        if (msg.callback != null) {        //如果接收到消息中,携带这个callback(线程),就执行这里的逻辑            handleCallback(msg);        } else {            if (mCallback != null) {                //如果实例话Handler时,实现回调接口并传入时就会执行实现逻辑                    return;                }            }            //如果上述2个条件都不符合,就执行这里了,比如,what=1            //因为这个就是一个空的方法            handleMessage(msg);        }    }

好了,Handler看了一下,大概明白这个消息机制是怎样的,接下来看看我们通过Handler发送消息的一些方法。

public final boolean sendMessage(Message msg) {       return sendMessageDelayed(msg, 0);   }  public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {  //延迟多少时间,常用啦     Message msg = Message.obtain();       msg.what = what;       return sendMessageDelayed(msg, delayMillis);   } /**延迟执行,一般我们在进入APP过渡界面,就会用到这个方法,或者是操作耗时任务的时候,耗时时间加上系统时间作为发送时间,*/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);     }

还有一些发送的方法我就不一 一列出了,通过上面的观察,可以发现,最后调用了sendMessageAtTime,在此方法内部有直接获取MessageQueue然后调用了enqueueMessage方法;

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;//把当前Handler的引用也一起传递过去,因为在Looper中通过Hnadler的引用来执行disptchMessage方法        if (mAsynchronous) {            msg.setAsynchronous(true);        }        //发送消息到消息队列        return queue.enqueueMessage(msg, uptimeMillis);    } //这个是MessageQueue的方法 boolean enqueueMessage(Message msg, long when) {        if (msg.target == null) {            throw new IllegalArgumentException            ("Message must have a target.");        }        if (msg.isInUse()) {            (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("MessageQueue", 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 (;;) {//如果消息队列有消息(正常情况下,那么该条消息就会被调到最后一条消息)                    //这个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;    }

这些总结是来自Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

这里我从一个handler发送消息---回调消息总结一下。

这里写图片描述

加上这个图是不是更清晰了,来写下代码,走下流程:
public class MainActivity extends Activity {    Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Message message = handler.obtainMessage();        message.what=1;        handler.sendMessage(message);    }
跟踪源码: handler.sendMessage(message);如下:1public final boolean sendMessage(Message msg){        return sendMessageDelayed(msg, 0);  }2public final boolean sendMessageDelayed(    Message msg, long delayMillis) {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(        msg, SystemClock.uptimeMillis() + delayMillis);    }3public 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);    }4private boolean enqueueMessage(        MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }   到了这一步,消息已经到了消息队列中了,我们就通过Looper无限循环抽取消息出来,然后通过:             //在一个无限循环中不断取出消息            Message msg = queue.next();            msg.target.dispatchMessage(msg);

再通过这个方法,回调到Hanlder中进行消息的处理!

  public void dispatchMessage(Message msg) {        if (msg.callback != null) {        //如果接收到消息中,携带这个callback(线程),就执行这里的逻辑            handleCallback(msg);        } else {            if (mCallback != null) {                //如果实例话Handler时,实现回调接口并传入时就会执行实现逻辑                    return;                }            }            //如果上述2个条件都不符合,就执行这里了,比如,what=1            //因为这个就是一个空的方法            handleMessage(msg);        }    }

大概我个人的理解就是这样了,如果那步不对,请指出,更正我的思路,哈哈,谢谢!

1 0
原创粉丝点击