Android消息循环机制

来源:互联网 发布:手机淘宝链接转换器 编辑:程序博客网 时间:2024/06/05 08:48

Android消息循环机制

Android消息循环机制

Android的消息循环机制主要先关的类有:

Handler

Looper

Message

MessageQueue

ActivityThread

一、为什么用Handler

Android又不建议在主线程中做耗时操作,比如IO操作、网络请求等操作,否则容易引起程序无法响应(ANR)。所以想这些耗时操作,都会放到其他的线程中进行处理,但是非UI线程又无法操作UIHandler的作用就是将一个任务切换到另外一个线程中执行。而我们主要用它来更新UI

二、Handler的基本使用

1

private Handler handler2 = new Handler(new Handler.Callback() {

@Override

public boolean handleMessage(Message msg) {

return false;

}

});

2

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

switch (msg.what){

case 1:

testview.setText("处理完毕");

break;

default:

break;

}

}

};


new Thread(){

@Override

public void run() {

// 一些耗时的操作

handler.sendEmptyMessage(1);

}

}.start();

3

handler.post(new Runnable() {

@Override

public void run() {

testview.setText("post");

}

});

4

handler.postDelayed(new Runnable() {

@Override

public void run() {

testview.setText("postDelayed");

}

}, 5000);

三、handle使用方法分为两套:“send”方法和“post”方法。

1send系列有7个方法,通过代码可以发现,重载方法相互调用,最终都是调用了enqueueMessage()方法。如下:

//1. 发送一个消息

public final boolean sendMessage(Message msg){

return sendMessageDelayed(msg, 0);

}


//2. 发送一个空消息

public final boolean sendEmptyMessage(int what){

return sendEmptyMessageDelayed(what, 0);

}


//3. 定时发送一个消息

public final boolean sendEmptyMessageAtTime(int what, longuptimeMillis) {

Message msg = Message.obtain();

msg.what = what;

return sendMessageAtTime(msg, uptimeMillis);

}


//4. 延迟发送一个空的消息,内部调用了sendMessageDelayed()方法

public final boolean sendEmptyMessageDelayed(int what, longdelayMillis) {

Message msg = Message.obtain();

msg.what = what;

return sendMessageDelayed(msg, delayMillis);

}


//5. 发送一个消息到消息队列的头部

public final boolean sendMessageAtFrontOfQueue(Message msg) {

MessageQueue queue = mQueue;

if (queue == null) {

RuntimeException e = new RuntimeException(

this + " sendMessageAtTime() called with nomQueue");

Log.w("Looper", e.getMessage(), e);

return false;

}

return enqueueMessage(queue, msg, 0);

}


// 6. 定时发送一个消息

public boolean sendMessageAtTime(Message msg, long uptimeMillis){

MessageQueue queue = mQueue;

if (queue == null) {

RuntimeException e = new RuntimeException(

this + " sendMessageAtTime() called with nomQueue");

Log.w("Looper", e.getMessage(), e);

return false;

}

return enqueueMessage(queue, msg, uptimeMillis);

}


//7. 延迟delayMillis时间发送一个消息

public final boolean sendMessageDelayed(Message msg, longdelayMillis){

if (delayMillis < 0) {

delayMillis = 0;

}

return sendMessageAtTime(msg, SystemClock.uptimeMillis() +delayMillis);

}


2post系列有5个方法,代码中可以看出,post的这几个方法都是调用的send的先关方法。只不过通过getPostMessage()的几个重载方法,将Runnable封装成了Message,代码如下:

public final boolean post(Runnable r){

return sendMessageDelayed(getPostMessage(r), 0);

}


public final boolean postDelayed(Runnable r, long delayMillis){

return sendMessageDelayed(getPostMessage(r), delayMillis);

}


public final boolean postAtTime(Runnable r, long uptimeMillis){

return sendMessageAtTime(getPostMessage(r), uptimeMillis);

}


public final boolean postAtFrontOfQueue(Runnable r){

return sendMessageAtFrontOfQueue(getPostMessage(r));

}


public final boolean postAtTime(Runnable r, Object token, longuptimeMillis){

return sendMessageAtTime(getPostMessage(r, token),uptimeMillis);

}


3、来看看getPostMessage的重载方法:

/**

* 设置消息对象的callback,返回Message对象

*当调用dispatchMessage()方法的时候,判断Messagecallback是否为空,不为空时,调用callbackrun()方法。

*/

private static Message getPostMessage(Runnable r) {

Message m = Message.obtain();

m.callback = r;

return m;

}


/**

* RunnableObject封装成一个Message对象返回。

*/

private static Message getPostMessage(Runnable r, Object token) {

Message m = Message.obtain();

m.obj = token;

m.callback = r;

return m;

}

一共有两个,都是通过Message.obtain()方法获取一个消息对象,然后重新对内部变量赋值,然后返回该Message对象。


3、不管是post方法,还是send方法,最后都牵扯到enqueueMessage这样一个方法。该方法内部,将messagetarget赋值为当前Handler对象,可见targetHandler类型的对象。最后调用了queue.enqueueMessage()对象。queueMessageQueue类型的变量,表示一个消息队列。消息队列实际上是通过单链表的结构来实现的。其内部逻辑,就是通过对when和当前对头指针的一些判断逻辑,进而将参数中的message添加到单单链表中。

/**

* message添加到消息队列

*/

private boolean enqueueMessage(MessageQueue queue, Message msg,long uptimeMillis) {

msg.target = this; // 这里将messagetarget对象赋为handler

if (mAsynchronous) {

msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg, uptimeMillis);

}


/**

* 消息入队操作

*/

boolean enqueueMessage(Message msg, long when) {

// ...

synchronized (this) {

// ...

msg.markInUse();

msg.when = when;

Message p = mMessages;

boolean needWake;

//mMessage为空或者when0后者when小于对头的when值时,将当前msg作为对头。

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 {

// msg添加到队列中间。

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;

}

// ...

}

return true;

}


四、总结

当我们使用Handler的时候,通过post或者send的一些列方法(post方法通过通过getPostMessage()方法将Runnable封装成Message对象调用send系列的方法实现,而getPostMessage()方法则调用Message.obtain()方法获取一个消息对象,不是立马创建一个消息对象,而是从消息池中获取,如果有就复用,没有就重新创建),把一个Message(消息)添加到MessageQueue(消息队列)中去,内部是单向链表。


五、Looper

Looper可以称之为“消息循环”。其主要作用是:当我们将消息放到消息队列之后,通过Looper管理消息队列,从队列中取出消息进行处理。

首先,Looper的构造函数是private类型,只能通过prepare(boolean)方法来进行初始化,并在构造函数中完成消息队列MessageQueue的初始化。如:主线程也就是ActivityThread,创建的时候会调用ActivityThread.main()方法,进而调用Looper.prepareMainLooper()——>Looper.prepare(boolean)方法,完成Looper对象的初始化(new了一个Looper对象),Looper的私有构造函数中正好创建了一个消息队列。一个线程只允许存在一个looper对象,否则会出现运行时异常,并通过ThreadLocal保存looper对象。

其次,当创建好looper对象后,然后通过Looper.loop()分发消息。loop()方法实际上建立了一个消息循环(死循环),一直从消息队列中读取消息,然后调用Messagetarget对象,实际上就是Handler对象的dispatchMessage(msg)方法进行处理。

六、Looper创建

首先,Looper的构造函数是private类型,只能通过prepare(boolean)方法来进行初始化,并在构造函数中完成消息队列MessageQueue的初始化。如:主线程也就是ActivityThread,创建的时候会调用ActivityThread.main()方法,进而调用Looper.prepareMainLooper()——>Looper.prepare(boolean)方法,完成Looper对象的初始化(new了一个Looper对象),Looper的私有构造函数中正好创建了一个消息队列。一个线程只允许存在一个looper对象,否则会出现运行时异常,并通过ThreadLocal保存looper对象。代码如下:


ActivityThread.Java 的部分源码:

static Handler sMainThreadHandler; // set once in main()

public static void main(String[] args) {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"ActivityThreadMain");

//...

Process.setArgV0("<pre-initialized>");

//初始化当前线程为looper

Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();

thread.attach(false);

if (sMainThreadHandler == null) {

sMainThreadHandler = thread.getHandler();

}

if (false) {

Looper.myLooper().setMessageLogging(new

LogPrinter(Log.DEBUG, "ActivityThread"));

}

// End of event ActivityThreadMain.

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

//开始运行线程中的消息队列 -- message queue

Looper.loop();

throw new RuntimeException("Main thread loop unexpectedlyexited");

}


Looper类部分源码:

static final ThreadLocal<Looper> sThreadLocal = newThreadLocal<Looper>();

private static Looper sMainLooper; // guarded by Looper.class

final MessageQueue mQueue;

final Thread mThread;

//系统调用此方法,初始化当前线程为looper,作为一个应用程序的主looper

public static void prepareMainLooper() {

prepare(false);

synchronized (Looper.class) {

if (sMainLooper != null) {

throw new IllegalStateException("The main Looper hasalready been prepared.");

}

sMainLooper = myLooper();

}

}


private static void prepare(boolean quitAllowed) {

if (sThreadLocal.get() != null) {//一个线程只允许存在一个looper对象。

throw new RuntimeException("Only one Looper may becreated per thread");

}

sThreadLocal.set(new Looper(quitAllowed));

}


//Looper构造函数--私有化

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}


//返回绑定到当前线程上的Looper对象

public static @Nullable Looper myLooper() {

return sThreadLocal.get();

}


七、Looper分发消息

当创建好looper对象后,然后通过Looper.loop()分发消息。loop()方法实际上建立了一个消息循环(死循环),一直从消息队列中读取消息,然后调用Messagetarget对象,实际上就是Handler对象的dispatchMessage(msg)方法进行处理。

代码如下:

public static void loop() {

final Looper me = myLooper();

if (me == null) {//如果menull,则表示没有调用prepare()方法。

throw new RuntimeException("No Looper; Looper.prepare()wasn't called on this thread.");

}

final MessageQueue queue = me.mQueue;// 1. 获取消息队列

// ...

for (;;) { // 2. 消息循环

Message msg = queue.next(); // 3. 获取消息(从消息队列中阻塞式的取出Message)

if (msg == null) {

// No message indicates that the message queue isquitting.

return;

}

// ...

//Message对象内部有一个Handler对象target。故,实际上调用的handlerdispatchMessage

// 故,实际上调用的handlerdispatchMessage(msg)方法进行分发。

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


if (logging != null) {

logging.println("<<<<< Finished to "+ msg.target + " " + msg.callback);

}

// ...

msg.recycleUnchecked();// 5. 回收消息

}

Handler.dispatchMessage(msg)

}


public void dispatchMessage(Message msg) {

if (msg.callback != null) {// message对象中Runnable类型的callback不为空时

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg); // 调用重写的方法

}

}


// 调用runnable类型的run()方法

private static void handleCallback(Message message) {

message.callback.run();

}

// 实现该接口时,重写该方法。

public interface Callback {

public boolean handleMessage(Message msg);

}


// 使用Handler的时候,会重写该方法。

public void handleMessage(Message msg) {

}

八、Handler构造:

  Handler有几个构造重载,如果构造时不提供Looper类对象参数,会获取当前线程的Looper对象,即将当前线程的消息循环作为Handler关联的消息循环。

  不是所有线程都有一个消息循环,主线程默认有looper对象,其他线程需要显式的创建作为参数传递给handler对象。如果当前线程没有looper,而构造Handler对象时又没有指定Looper对象,则会抛出一个运行时异常:

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException("Can't create handler insidethread that has not called Looper.prepare()");

}




九、综述:

如图


1)程序启动的时候,主线程会创建一个Looper对象。Looper对象内部维护一个MessageQueue,然后调用loop()方法循环去读取消息。

具体操作如下:首先,Looper的构造函数是private类型,只能通过prepare(boolean)方法来进行初始化,并在构造函数中完成消息队列MessageQueue的初始化。如:主线程也就是ActivityThread,创建的时候会调用ActivityThread.main()方法,进而调用Looper.prepareMainLooper()——>Looper.prepare(boolean)方法,完成Looper对象的初始化(new了一个Looper对象),Looper的私有构造函数中正好创建了一个消息队列。一个线程只允许存在一个looper对象,否则会出现运行时异常,并通过ThreadLocal保存looper对象。

其次,当创建好looper对象后,然后通过Looper.loop()分发消息。loop()方法实际上建立了一个消息循环(死循环),一直从消息队列中读取消息,然后调用Messagetarget对象,实际上就是Handler对象的dispatchMessage(msg)方法进行处理。

2)初始化Handler的时候,在Handler的构造函数内部,会获取当前线程的Looper对象,进而获取MessageQueue对象。由此可见,想要操作UIHandler必须在主线程中创建。

3)调用Handler的相关发送消息方法时,会获取Message对象,将消息对象的target指向当前handler对象,然后放到消息队列中。Message内部维护一个消息池,用来回收缓存message对象。

当我们使用Handler的时候,通过post或者send的一些列方法(post方法通过通过getPostMessage()方法将Runnable封装成Message对象调用send系列的方法实现,而getPostMessage()方法则调用Message.obtain()方法获取一个消息对象,不是立马创建一个消息对象,而是从消息池中获取,如果有就复用,没有就重新创建),把一个Message(消息)添加到MessageQueue(消息队列)中去,内部是单向链表。

4loop()工作中,会从消息队列中获取一个个的消息,调用handledispatchMessage(msg)分发处理。





参考http://www.2cto.com/kf/201606/518409.html



原创粉丝点击