Android - Handler 、AsyncTask(一)
在android中,更新UI的操作都必须在主线程中进行,不能做阻塞主线程的操作。
当我们要执行一个耗时的操作并且最终要去更新UI(比如将计算结果反映到UI上)时,我们会考虑新开一个线程,去执行这个耗时的操作,执行完毕之后,再在主线程中更新UI。
为了解决这种问题,android为我们提供了很多办法。
一、handler和message机制
下边这个小Demo演示了Handler最简单常见的用法,在新开的线程里模拟一个耗时的操作timeConsumingOperation(),操作完成后利用handler.sendEmptyMessage(0)发送消息,然后在主线程中mProgressDialog.dismiss()更新UI:
public class MainActivity extends Activity implements OnClickListener{
private Button mButton;
private ProgressDialog mProgressDialog;
private Handler handler = new Handler(){
public void handleMessage(Message msg){
super.handleMessage(msg);
mProgressDialog.dismiss();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton= (Button)findViewById(R.id.button1);
mButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
newThread();
}
private void newThread(){
mProgressDialog= ProgressDialog.show(this, "提示", "正在下载,请稍后 ……");
new Thread(){
public void run(){
timeConsumingOperation();
handler.sendEmptyMessage(0);
}
}.start();
}
private void timeConsumingOperation(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述代码中,发送消息的 sendEmptyMessage() 方法是由Handler的子类对象调用的,更新UI的方法mProgressDialog.dismiss()也是在Handler的子类复写的handleMessage()方法中定义的,所以我们先从创建Handler的子类对象new Handler()讲起
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.
... ...
//一个Handler允许你发送和处理和一个线程的Message Queue相关联的Message和Runnable对象,
//每一个Handler和一个线程及线程的Message Queue相关联... ...
public class Handler {
......
(注释太多不全列出了)通常我们执行new Handler()时,以下构造函数会被调用:
public Handler(Callback callback, boolean async) {
... ...
final MessageQueue mQueue;
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 = callback;
... ...
其中mLooper是Handler的成员变量final Looper mLooper, Looper类的作用是管理此线程里的Message Queue。先来看看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.
*/
public final class Looper {}
此类用来为一个线程run一个message loop,一个线程默认是没有和其关联的message loop的,如果想要创建,则调用prepare方法,然后调用loop方法来处理消息......
而myLooper()方法的注释如下:
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
//该方法用于获取当前线程的Looper对象,如果没有则返回null
public static Looper myLooper() {
return sThreadLocal.get();
}
该方法用于获取当前线程的Looper对象,如果没有则返回null
需要注意的是:系统默认为主线程而没有为子线程创建looper对象,所以在子线程中直接new Handler()会报如下错误(参考public Handler(Callback callback, boolean async)方法):
"Can't create handler inside thread that has not called Looper.prepare()");
我们来看看系统在主线程中创建looper对象的相关代码,从ActivityThread.java中我们可以看到:
public static void main(String[] args) {
... ...
Looper.prepareMainLooper();
... ...
Looper.loop();
... ...
}
其中,prepareMainLooper()方法的注释如下:
/**
* 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. See also: {@link #prepare()}
*/
//初始化当前的线程为一个looper线程,标记它为一个应用的main looper,应用的main looper为系统自动创建,你不需要自己调用该方法
public static void prepareMainLooper() {
prepare(false);
... ...
}
prepare()方法的注释如下:
/** 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()}.
*/
//初始化当前线程为一个looper线程,这使得你有机会去创建一个handler,在调用这个方法之后,在想正式开始loop之前
//记得调用loop方法,最后调用quit方法end it
public static void prepare() {
prepare(true);
}
loop()方法的注释如下:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
//让这个线程里的message queue run起来,确保调用quit方法来end the loop
public static void loop() {
... ...
同样,我们如果需要在子线程中new Handler,也需要调用Looper.prepare()和Looper.loop()两个方法,正如API中对looper类的介绍一样:
/**
* <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 final class Looper {}
接下来,我们看prepare()方法的主要逻辑:
public final class Looper {
final MessageQueue mQueue;
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
... ...
sThreadLocal.set(new Looper(quitAllowed));
... ...
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
... ...
}
}
可以看到,无论是在主线程的prepareMainLooper()方法中还是我们手动调用prepare()方法,都会在创建Looper对象的同时创建一个Message Queue对象赋给Looper的成员变量final MessageQueue mQueue

/**
* 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 final class MessageQueue {
而我们new Handler 时,在public Handler(Callback callback, boolean async)方法中,在通过Looper.myLooper()方法得到线程对应的Looper对象后,将该Looper对象的成员变量mQueue再赋给Handler的final MessageQueue mQueue,所以,一个Handler对象对应一个线程对应一个Looper对象对应一个MessageQueue 。
/**
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
* If you don't want that facility, just call Message.obtain() instead.
*/
//直接从message pool中返回一个message,这将比直接创建一个message更有效率,返回的message已经有了和它关联的handler(这是
//在Message类中的obtain(Handler h)方法中通过m.target = h实现的),你也可以直接调用Message.obtain()方法来创建消息
public final Message obtainMessage(){
return Message.obtain(this);
}
二、灵活性上的区别
/**
* Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
* <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
*/
public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
第一句,Message m = obtain();我们来看obtain()方法的注释:
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
//从global pool中返回一个新的message对象,能避免我们在很多情况下去新建对象
public static Message obtain() {
... ...
}
在获得一个Message对象之后,接着为它的成员变量赋值:m.what = what 、m.arg1 = arg1 ,等等。
public final class Message implements Parcelable {
/**
* User-defined message code so that the recipient can identify
* what this message is about. Each {@link Handler} has its own name-space
* for message codes, so you do not need to worry about yours conflicting
* with other handlers.
*/
//可以理解为一个用于区分消息的标示符
public int what;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
//如果你只是想携带一些比较简单的integer数据的话,相对于setData(Bundle)方法来讲
//arg1和arg2是一种比较低耗的选择
public int arg1;
/**
* arg1 and arg2 are lower-cost alternatives to using
* {@link #setData(Bundle) setData()} if you only need to store a
* few integer values.
*/
public int arg2;
Bundle data;
Handler target;
Runnable callback; ... ...
}
1、最常用的what,可以理解为是一个对message进行区分的标示符。
Bundle mBundle = new Bundle();
mBundle.putBoolean("myKey1", true);
mBundle.putString("myKey2", "myValue");
Message mMessage = Message.obtain(handler, 5, 111, 112, mBundle);
//或者:
Bundle mBundle = new Bundle();
mBundle.putBoolean("myKey1", true);
mBundle.putString("myKey2", "myValue");
Message mMessage = new Message();
mMessage.setData(mBundle);
//在接收到message时,可以通过Message的getData()方法获取mBundle对象
在这里,我们也可以感受到 在为获得Message对象的obtain()方法的参数中 加入Object obj的作用,它 让message的创建有了更好的扩展性。
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
/**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
//发送一条仅仅含有what值得消息,返回true(false)如果(没有)成功将消息发送到消息队列
public final boolean sendEmptyMessage(int what){
return sendEmptyMessageDelayed(what, 0);
}
sendMessage()方法是将一个(不管通过什么方式)已经构建好的Message对象放到消息队列中,而sendEmptyMessage(int what)方法,则是先通过Message.obtain()获得一个Message,将what值赋给Message的what变量:msg.what = what,再将消息发送到消息队列。
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
* @param r The Runnable that will be executed.
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
需要说明的是,post(Runnable r)方法和sendMessage(Message msg)方法都调用了sendMessageDelayed(Message msg, long delayMillis)方法,只不过post(Runnable r)方法中,先通过getPostMessage(r)获取了 一个成员变量Runnable callback的值为Runnable r 的Message对象,下面是getPostMessage(Runnable r)的源码:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
在讲消息处理之前,还需要提到的是,我们可以从Handler.java中看到,无论调用哪个send和post方法来发送message,最终都会调用enqueueMessage()方法,我们来看源码:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在enqueueMessage()方法的第一行,先执行msg.target = this,将发送消息的这个handler赋值给Message的成员变量Handler target,然后再将消息发送到消息队列
public static void loop() {
for (;;) {
Message msg = queue.next();
msg.target.dispatchMessage(msg);
}
}
在loop()方法中,循环从MessageQueue中获取Message对象(Message msg = queue.next();),然后调用 msg.target.dispatchMessage(msg)方法进行处理,哪个handler发送的消息就由哪个handler来处理,而我们在讲发送消息时也做过铺垫了。来看dispatchMessage()方法的定义:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
首先判断,如果(msg.callback != null),则执行handleCallback(msg),所以由post发送过来的Runnable对象,在处理的时候执行的就是handleCallback(msg)方法,来看该方法的定义:
private static void handleCallback(Message message) {
message.callback.run();
}
如果(msg.callback == null),则执行handleMessage(msg)方法,来看该方法在Handler类中的定义:
/**
* Subclasses must implement this to receive messages.
*/
//子类必须实现该方法来处理消息
public void handleMessage(Message msg) {
//空的
}
我们从一个简单常见的例子入手,先以Handler对象的创建为出发点,大致将Handler、Looper和MessageQueue 的相互关系理清,接下来,分析在子线程中创建消息、发送消息和在主线程中处理消息的过程及在这些过程中的常用方法。
浙公网安备 33010602011771号