您的位置:首页 > 产品设计 > UI/UE

Android异步处理——Handler、Looper、Message、MessageQueue

2015-12-20 14:46 453 查看
Android异步处理是日常中常见的做法:当你在做耗时操作的时候,开个线程。如果需要更新UI,那么你最常用的就应该是Handler这个机制了。

网上对Handler机制的描述很多,如果不了解的,可以先看看以下网址上的解释,十分详尽:

http://blog.csdn.net/guolin_blog/article/details/9991569

这里,主要是讲Handler在应用中,需要注意的问题与用法。

首先,我们要了解Handler、Looper、Message、MessageQueue这四个主要元素是怎么联合、运行的呢?

Handler,主要用于发送Message和处理Message;

Message,就是我们想要处理的信息;

MessageQueue,是一个消息队列,需要处理消息的集中地;

Looper,这就是一个消息的搬运工,从MessageQueue中不停的取出消息。

在代码中,我们习惯的一种写法就很好的说明了以上各部分的作用:

Message组装(比如:Message msg=Message.obtain();)——>handler.sendMessage(...)——>Looper.loop()——handler.handleMessage()。

了解了基本的一些信息,今天要介绍的主要有三块细分内容:

1、Handler定义在主线程;

2、Handler定义在子线程;

3、Message的组装;

Handler定义在主线程

这应该是我们最常用到的一种形式,在主线程开启一个子线程用于耗时操作,子线程执行过程中,通过Handler更新主线程UI。
按我们上面介绍的逻辑,写法如下:
组装好Message,并用定义好的Handler发送消息
Message message=Message.obtain();
message.what=1;
myHandler.sendMessage(message);
以下是定义的Handler。重写Handler的处理方法handleMessage
private   Handler myHandler=new Handler() {

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.i(tag,"handler的Thread id="+Thread.currentThread().getId());
super.handleMessage(msg);
switch (msg.what) {
case 1:
Log.i(tag, msg.what+"");
break;

default:
break;
}
}

};
因为我们将Handler定义在主线程上,因此handleMessage中的log,打印出来的线程id为1.
只看以上的两段代码,是不是感觉缺少了什么?说好的Looper呢,MessageQueue呢,没看到啊。
其实,仔细看前面网址中的文章,你应该看到主线程自动帮你做了Looper的操作,Looper.prepare()绑定了一个MessageQueue。这样元素就齐全了。
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}


Handler定义在子线程

相信你可能也想到Handler定义在子线程,没有定义在主线程的那种便利了。因为子线程不会自动帮你做Looper的prepare以及loop操作。
如果你还按照主线程的写法。那么,它会提示你,你写错了:Can't create handler inside thread that has not calledLooper.prepare()。
提示很明显,在子线程中创建Handler不能缺少Looper.prerare()。
我们要修改下写法:
private void thread() {
new Thread(new Runnable() {

@Override
public void run() {

Log.i(tag, "prepare前的thread id="+Thread.currentThread().getId());
if(Looper.myLooper()==null)
{
Log.i(tag, "Looper.myLooper()=null");
}
Looper.prepare();
if(Looper.myLooper()!=null)
{
Log.i(tag, "Looper.myLooper()="+Looper.myLooper());
}
Log.i(tag, "prepare后的thread id="+Thread.currentThread().getId());
HandlerImp handlerImp=new HandlerImp();
handlerImp.goThread();
Looper.loop();
}
}).start();
}
也贴出HandlerImp的语句:
package com.example.handler_csdn;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Handler.Callback;
import android.util.Log;

public class HandlerImp {

static String tag="tag";
//这里可以是主线程或者子线程。
//当调用这个类的时候,在子线程中调用,则handler在子线程中
//当调用这个类的时候,在主线程中调用,则handler在主线程中

private Handler myHandler=CommonHandler.getInstance().getHandler(new Callback() {

@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.i(tag,"handler的Thread id="+Thread.currentThread().getId());
switch (msg.what) {
case 1:
Log.i(tag, msg.what+"");
break;

default:
break;
}
return true;
}
});

public void goThread() {

//此处进入子线程
new Thread(new task()).start();
}

class task implements Runnable
{
@Override
public void run() {
// TODO Auto-generated method stub

Message message=Message.obtain(); message.what=1; myHandler.sendMessage(message);
}

}
}
简单的就是,开启线程后,我们首先做的是Looper.prepare(),它的作用是如果没有消息队列,开启一个(有且只有一个)消息队列,用于Message的进出。之后将消息发送到MessageQueue中。之后,用Looper.loop(),取消息。最后处理。
这个就与我们的逻辑是相符的。这么做后,在子线程中就能正常的使用Handler了。

Handler在主线程和子线程的统一定义

现在通过以上的说明,我们知道在Handler的处理上,主线程和子线程是不一样的。但,如果需要我们提供一个API供其他人使用,而我们的API中含有Handler的处理。那么我们要怎么定义呢?因为我们不知道用户是在主线程还是子线程中使用我们定义的API,这两种情况,都需要考虑到。
鉴于以上的情况,我们将以上两部分结合在一起,写成一个类:
package com.example.handler_csdn;

import android.os.Handler;
import android.os.Looper;
import android.os.Handler.Callback;
import android.util.Log;

public class CommonHandler {

private static CommonHandler commonHandler;
public static CommonHandler getInstance()
{
synchronized (CommonHandler.class) {
if (commonHandler == null) {
commonHandler=new CommonHandler();
}
return commonHandler;
}
}

public  Handler getHandler(Callback callback)
{
Handler handler = null;
if(isMainThread())
{
handler=new Handler(Looper.getMainLooper(),callback);
}
else {
Log.i("tag", "此处的thread id="+Thread.currentThread().getId());
if(Looper.myLooper()==null)
{
handler=new Handler(Looper.getMainLooper(),callback);
}
else {
handler=new Handler(callback);
}

}
return handler;

}

public  boolean isMainThread()
{
if(Looper.getMainLooper().getThread()==Thread.currentThread())
{
return true;
}
return false;
}

}
如上,判断是否主线程,如果不是,则采用子线程的处理方式。这样就能让用户能正常的使用我们的API。

Message的组装

Message的定义,我们有好几种形式。它本身也有很多种重载。
比如:
Message msg=new Message();
Message msg=Message.obtain();
主要是以上的两种形式和他们各自的重载。一般我们采用的是第二种格式,因为这种写法,Android底层为我们封装好了,里面是回收再利用机制,避免了new Message多重导致的内存消耗问题。

以上,就是Handler的简单介绍。

源码

源码地址如下:
http://download.csdn.net/my/uploads
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息