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的组装;
按我们上面介绍的逻辑,写法如下:
组装好Message,并用定义好的Handler发送消息
只看以上的两段代码,是不是感觉缺少了什么?说好的Looper呢,MessageQueue呢,没看到啊。
其实,仔细看前面网址中的文章,你应该看到主线程自动帮你做了Looper的操作,Looper.prepare()绑定了一个MessageQueue。这样元素就齐全了。
如果你还按照主线程的写法。那么,它会提示你,你写错了:Can't create handler inside thread that has not calledLooper.prepare()。
提示很明显,在子线程中创建Handler不能缺少Looper.prerare()。
我们要修改下写法:
这个就与我们的逻辑是相符的。这么做后,在子线程中就能正常的使用Handler了。
鉴于以上的情况,我们将以上两部分结合在一起,写成一个类:
比如:
Message msg=new Message();
Message msg=Message.obtain();
主要是以上的两种形式和他们各自的重载。一般我们采用的是第二种格式,因为这种写法,Android底层为我们封装好了,里面是回收再利用机制,避免了new Message多重导致的内存消耗问题。
以上,就是Handler的简单介绍。
http://download.csdn.net/my/uploads
网上对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;简单的就是,开启线程后,我们首先做的是Looper.prepare(),它的作用是如果没有消息队列,开启一个(有且只有一个)消息队列,用于Message的进出。之后将消息发送到MessageQueue中。之后,用Looper.loop(),取消息。最后处理。
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);
}
}
}
这个就与我们的逻辑是相符的。这么做后,在子线程中就能正常的使用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
相关文章推荐
- Android开发笔记之:Handler Runnable与Thread的区别详解
- android的消息处理机制(图文+源码分析)―Looper/Handler/Message
- Android中的Looper对象详细介绍
- Android消息处理机制Looper和Handler详解
- AsyncTask陷阱之:Handler,Looper与MessageQueue的详解
- Android中的Handler与多线程应用实例
- android开发教程之handler异步更新ui
- Android定时器和Handler用法实例分析
- Toast和Handler的间隔使用实例
- Android中AsyncTask与handler用法实例分析
- android开发教程之android的handler使用方法
- 详解Android中Handler的使用方法
- 详解Android中Handler的内部实现原理
- Android通过Handler与AsyncTask两种方式动态更新ListView(附源码)
- Android开发笔记 Handler使用总结
- Android Looper简介
- Android Handler
- Handler的基本使用
- Loadrunner message函数详细分析