Android异步处理

Android异步处理机制:Handler,Looper,Mes

2016-07-19  本文已影响53人  狮_子歌歌

Android异步处理机制:Handler,Looper,MessageQueue

异步处理消息概念:

异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。

Handler,Looper,MessageQueue三者的关系

每一个线程都拥有一个Looper对象,每一个Looper对象都持有一个MessageQueue(先进先出)。一个Looper可以和多个线程的Handler绑定起来。总结:Looper的创建会持有一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中获取消息,而消息的发送者可以是一个或者多个Handle。


解析

Looper

Looper的构造方法

private Looper(boolean quitAllowed) {
        //创建了一个消息队列  
        mQueue = new MessageQueue(quitAllowed);  
        mRun = true;  
        mThread = Thread.currentThread();  
}  

Looper.prepare()

public static final void prepare() {
        //sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量  
        if (sThreadLocal.get() != null) {  
            throw new RuntimeException("Only one Looper may be created per thread");  
        }  
        sThreadLocal.set(new Looper(true));  
}  

说明一个looper对象与对应线程绑定,且该线程有且仅有一个looper对象。如果第二次调用looper.prepare()方法会抛出异常。

Looper.loop()

public static void loop() {  
        final Looper me = myLooper();
        //如果me为null说明在调用loop()方法之前没有为当前线程创建Looper对象,抛出异常。  
        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.  
        Binder.clearCallingIdentity();  
        final long ident = Binder.clearCallingIdentity();  
        //进入无限循环,不断的从messageQueue中获取消息
        for (;;) {
            //从队列获取消息  
            Message msg = queue.next(); // might block 
            //如果消息是空,则队列中没有消息,return结束loop()方法,线程阻塞等待 
            if (msg == null) {  
                // No message indicates that the message queue is quitting.  
                return;  
            }  
  
            ...  
            //使用调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。msg中的target就是handle。
  
            msg.target.dispatchMessage(msg);  
  
            ...  
            //释放消息占据的资源
  
            msg.recycle();  
        }  
} 
/**
*获取线程ThreadLocal属性存储的looper对象
**/ 
public static Looper myLooper() {
        return sThreadLocal.get();
}

综上所述,looper的作用就是与当前线程绑定,并且该线程只有一个looper。同时,looper持有一个MessageQueue,有且仅有一个。loop()方法无限循环的从MessageQueue中读取消息,并将message交给message的target的dispatchMessage(msg)处理。

Handler

Handler的构造方法

在使用Handler之前,我们必须对其实例化。

Handler必须和线程绑定在一起,在初始化Handler的时候一般通过指定Looper对象来绑定looper所在的线程,即给Handler指定Looper对象等于绑定到了Looper对象所在的线程中。Handler的消息处理回调会在该线程中执行。

public Handler() {  
        this(null, false);  
}  
public Handler(Callback callback, boolean async) {  
        ... 
        //首先获取当前线程保存的looper对象,
        mLooper = Looper.myLooper();  
        if (mLooper == null) {  
            throw new RuntimeException(  
                "Can't create handler inside thread that has not called Looper.prepare()");  
        }  
        //然后与该looper持有的MessageQueue绑定。
        mQueue = mLooper.mQueue;  
        mCallback = callback;  
        mAsynchronous = async;  
    }

如果没有指定looper,那么handler会与当前创建handler的线程绑定,其消息回调处理也在该线程中执行。
可以通过Looper.myLoop()得到当前线程的looper对象或者调用Looper.getMainLooper()获得主线程的looper对象。

Handler向MessageQueue发送消息

handler send

最常用的sendMessage()方法

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);  
} 
 
 
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) {
        //将handler实例赋值给msg的target属性。  
       msg.target = this;  
       if (mAsynchronous) {  
           msg.setAsynchronous(true);  
       }  
       //调用消息队列的enqueueMessage()方法,
       //就是将handler发送的消息保存到消息队列中去
       return queue.enqueueMessage(msg, uptimeMillis);  
} 

Looper的loop()方法会取出每个msg然后执行msg.target.dispatchMessage(msg)去处理消息,其实就是派发给相应的Handler。

Handler工作流程:在线程中通过Looper.prepare()方法为当前线程创建Looper对象,并调用Looper.loop()方法无限循环地从messageQueue中获取handler发送过来的消息,并回调handler。dispatchMessage()方法

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  
        handleCallback(msg);  
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }
        //调用handler的sendMessage()方法,在源码中是一个空方法体。
        //也就是我们在实例化Handler对象时,需要去覆写它,实现自己的处理逻辑。  
        handleMessage(msg);  
    }  
} 

注:在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢?这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

Handler post
mHandler.post(new Runnable()  
        {  
            @Override  
            public void run()  
            {  
                Log.e("TAG", Thread.currentThread().getName());  
                mTxt.setText("yoxi");  
            }  
        });

Handler.post()方法中Runnable并没有创建线程。在这个run()方法中可以更新UI。其实Runnable只是发送了一条消息。

public final boolean post(Runnable r) {  
      return  sendMessageDelayed(getPostMessage(r), 0);  
} 
   
private static Message getPostMessage(Runnable r) {  
      Message m = Message.obtain();  
      m.callback = r;  
      return m;  
}  

由此可见,源码中只是将Runnable对象作为message的callback属性。

注:产生一个Message对象,可以new ,也可以使用Message.obtain()方法;两者都可以,但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。

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

最终和handler.sendMessage一样,调用了sendMessageAtTime,然后调用了enqueueMessage方法,给msg.target赋值为handler,最终加入MessagQueue.
由于在getPostMessage()方法中我们给message的callback属性赋值(Runnable),所以这里需要进行判断到底回调handler还是runnable。

public void dispatchMessage(Message msg) { 
     //判断message对象的callback属性是否存在,若存在执行handlerCallback()方法。
     //即调用runnable 
    if (msg.callback != null) {  
        handleCallback(msg);  
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
} 

MessageQueue

消息队列,用于存放handler发送过来的message
MessageQueue.enqueueMessage()方法将handler发送的消息插入队列中。MessageQueue.next()将消息按照先进先出的顺序取出。

总结

为了实现Android的UI线程安全,UI的相关操作只能在主线程(UI线程)中操作。但在开发中,需要开启多线程处理耗时操作,又要修改UI,所以就有了Handler传递机制。

[主线程(UI线程)定义:当程序第一次启动时,Android会同时启动一条主线程(Main Thread)
作用:主线程主要负责处理与UI相关的事件,所以主线程又叫UI线程)]

使用runOnUIThread()方法更新UI

public final void runOnUiThread(Runnable action) {  
        if (Thread.currentThread() != mUiThread) {  
            mHandler.post(action);  
        } else {  
            action.run();  
        }  
    } 

从源码来看,首先判断当前线程是否是UI线程,如果不是,通过主线程的Handler来发送Runnable对象,实现当前线程与UI线程之间的信息传递;若当前线程是UI线程,则直接调用执行Runnable的run()方法。

参考文献

鸿洋大神文章

上一篇下一篇

猜你喜欢

热点阅读