Android Handler在新线程中处理消息
2016-01-07 11:52
525 查看
搜罗了些handler的内容,留着自己看吧
在主线程中,使用handler很简单,new一个Handler对象实现其handleMessage方法,在handleMessage中提供收到消息后相应的处理方法即可。
在Java中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象。
当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用
(不然你怎么可能通过Handler来操作Activity中的View?)。
在自己new一个新线程中去像我前面那样简单建立一个Handler,程序执行是会报错的:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at com.cao.android.demos.handles.HandleTestActivity$MyThread$1.<init>(HandleTestActivity.java:86)
at com.cao.android.demos.handles.HandleTestActivity$MyThread.run(HandleTestActivity.java:86)
为什么在主线程中不会报错,而在自己新见的线程中就会报这个错误呢?很简单,因为主线程它已经建立了Looper,你可以打开ActivityThread的源码看一下:
public static final void main(String[] args) {
SamplingProfilerIntegration.start();
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
}
thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}
在main函数中它已经做了这个事情了,为什么要调用 Looper.prepareMainLooper(); Looper.loop();我们可以进去看一下,在prepareMainLooper方法中新建了一个looper对象,并与当前进程进行了绑定,而在Looper.loop方法中,线程建立消息循环机制,循环从MessageQueue获取Message对象,调用
msg.target.dispatchMessage(msg);进行处理msg.target在myThreadHandler.sendEmptyMessage(0)设置进去的,因为一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理,那么Handler又是怎样与Looper建立联系的呢,在Handler构造函数中有这样一段代码:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
在新建Handler时需要设置mLooper成员,Looper.myLooper是从当前线程中获取绑定的Looper对象:
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
若Looper对象没有创建,就会抛异常"Can't create handler inside thread that has not called Looper.prepare()"
这跟我前面讲的是一致的。所以我们在一个新线程中要创建一个Handler就需要这样写:
class MyThread extends Thread {
public void run() {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]-- run...", Thread
.currentThread().getName()));
// 其它线程中新建一个handler
Looper.prepare();// 创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper
myThreadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler handleMessage run...", Thread
.currentThread().getName()));
}
};
Looper.myLooper().loop();//建立一个消息循环,该线程不会退出
}
}
现在,你应该对Handler的机制有所了解了吧,若有什么疑问,欢迎在评论中提出
在其它线程中Handler使用主线程的Looper
前面我说了在新线程中要新建一个Handler需要调用Looper.prepare();也有另一种方法就是使用主线程中的Looper,那就不必新建Looper对象了:
threadMainLoopHandler =new Handler(Looper.getMainLooper()){
public void handleMessage(android.os.Message msg) {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--threadMainLoopHandler handleMessage run...", Thread
.currentThread().getName()));
}
//该handleMessage方法将在mainthread中执行
};
这时候注意不要在handleMessage做太多的操作,因为它在主线程中执行,会影响主线程执行ui更新操作。
使用Message.callback回调
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
从dispatchMessage定义可以看出,如果Message对象自带callback对象,handler不会执行handleMessage方法而是执行message.callback中定义的run方法,当然callback还是在handler关联的looper所绑定的线程中执行的。实际上Handler.post(Runnable r)方法就是把r添加到一个msg.callback的,也就是说,下面两种写法,没有什么区别:
1.使用Message.callback
[java] view
plaincopy
Message msg = Message.obtain(myThreadHandler,new Runnable() {
@Override
public void run() {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",
Thread.currentThread().getName()));
}
});
myThreadHandler.sendMessage(msg);
2.使用Handler.post
[java] view
plaincopy
myThreadHandler.post(new Runnable() {
@Override
public void run() {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",
Thread.currentThread().getName()));
}
});
利用android开发框架中的looper类来实现:
首先创建一个HandlerThread新线程并调用start方法:
[html] view
plaincopy
HandlerThread handlerThread = new HandlerThread("handler_thread");
handlerThread.start();
将handlerThread的looper作为参数绑定到一个继承handler的子类线程中:
[html] view
plaincopy
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
}
}
在handlerMessage方法中处理消息。
在实例中:
[html] view
plaincopy
package cn.android.handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class HandlerTestActivity extends Activity {
/** Called when the activity is first created. */
private static final String SWORD="SWORD";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//打印当前线程ID
Log.i(SWORD,"Activity--->"+Thread.currentThread().getId());
//生成一个HandlerThread对象,实现了使用Looper来处理消息队列
HandlerThread handlerThread = new HandlerThread("handler_thread");
//在使用HandlerThread的getLooper()方法之前,必须先调用该类的start()方法启动线程
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
Message msg = myHandler.obtainMessage();
//将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象
Bundle b = new Bundle();
b.putInt("age", 20);
b.putString("name", "Jhon");
msg.setData(b);
//发送消息对象
msg.sendToTarget();
}
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
Bundle b = msg.getData();
int age = b.getInt("age");
String name = b.getString("name");
Log.i(SWORD,"age--"+age+" name---"+name);
Log.i(SWORD,"handlerId"+Thread.currentThread().getId());
Log.i(SWORD,"handlerMessage");
}
}
}
运行并查看日志输出结果:
在主线程中,使用handler很简单,new一个Handler对象实现其handleMessage方法,在handleMessage中提供收到消息后相应的处理方法即可。
在Java中,非静态(匿名)内部类会默认隐性引用外部类对象。而静态内部类不会引用外部类对象。
当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用
(不然你怎么可能通过Handler来操作Activity中的View?)。
在自己new一个新线程中去像我前面那样简单建立一个Handler,程序执行是会报错的:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at com.cao.android.demos.handles.HandleTestActivity$MyThread$1.<init>(HandleTestActivity.java:86)
at com.cao.android.demos.handles.HandleTestActivity$MyThread.run(HandleTestActivity.java:86)
为什么在主线程中不会报错,而在自己新见的线程中就会报这个错误呢?很简单,因为主线程它已经建立了Looper,你可以打开ActivityThread的源码看一下:
public static final void main(String[] args) {
SamplingProfilerIntegration.start();
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
}
thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}
在main函数中它已经做了这个事情了,为什么要调用 Looper.prepareMainLooper(); Looper.loop();我们可以进去看一下,在prepareMainLooper方法中新建了一个looper对象,并与当前进程进行了绑定,而在Looper.loop方法中,线程建立消息循环机制,循环从MessageQueue获取Message对象,调用
msg.target.dispatchMessage(msg);进行处理msg.target在myThreadHandler.sendEmptyMessage(0)设置进去的,因为一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理,那么Handler又是怎样与Looper建立联系的呢,在Handler构造函数中有这样一段代码:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
在新建Handler时需要设置mLooper成员,Looper.myLooper是从当前线程中获取绑定的Looper对象:
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
若Looper对象没有创建,就会抛异常"Can't create handler inside thread that has not called Looper.prepare()"
这跟我前面讲的是一致的。所以我们在一个新线程中要创建一个Handler就需要这样写:
class MyThread extends Thread {
public void run() {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]-- run...", Thread
.currentThread().getName()));
// 其它线程中新建一个handler
Looper.prepare();// 创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper
myThreadHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler handleMessage run...", Thread
.currentThread().getName()));
}
};
Looper.myLooper().loop();//建立一个消息循环,该线程不会退出
}
}
现在,你应该对Handler的机制有所了解了吧,若有什么疑问,欢迎在评论中提出
在其它线程中Handler使用主线程的Looper
前面我说了在新线程中要新建一个Handler需要调用Looper.prepare();也有另一种方法就是使用主线程中的Looper,那就不必新建Looper对象了:
threadMainLoopHandler =new Handler(Looper.getMainLooper()){
public void handleMessage(android.os.Message msg) {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--threadMainLoopHandler handleMessage run...", Thread
.currentThread().getName()));
}
//该handleMessage方法将在mainthread中执行
};
这时候注意不要在handleMessage做太多的操作,因为它在主线程中执行,会影响主线程执行ui更新操作。
使用Message.callback回调
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
从dispatchMessage定义可以看出,如果Message对象自带callback对象,handler不会执行handleMessage方法而是执行message.callback中定义的run方法,当然callback还是在handler关联的looper所绑定的线程中执行的。实际上Handler.post(Runnable r)方法就是把r添加到一个msg.callback的,也就是说,下面两种写法,没有什么区别:
1.使用Message.callback
[java] view
plaincopy
Message msg = Message.obtain(myThreadHandler,new Runnable() {
@Override
public void run() {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",
Thread.currentThread().getName()));
}
});
myThreadHandler.sendMessage(msg);
2.使用Handler.post
[java] view
plaincopy
myThreadHandler.post(new Runnable() {
@Override
public void run() {
Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",
Thread.currentThread().getName()));
}
});
利用android开发框架中的looper类来实现:
首先创建一个HandlerThread新线程并调用start方法:
[html] view
plaincopy
HandlerThread handlerThread = new HandlerThread("handler_thread");
handlerThread.start();
将handlerThread的looper作为参数绑定到一个继承handler的子类线程中:
[html] view
plaincopy
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
}
}
在handlerMessage方法中处理消息。
在实例中:
[html] view
plaincopy
package cn.android.handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class HandlerTestActivity extends Activity {
/** Called when the activity is first created. */
private static final String SWORD="SWORD";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//打印当前线程ID
Log.i(SWORD,"Activity--->"+Thread.currentThread().getId());
//生成一个HandlerThread对象,实现了使用Looper来处理消息队列
HandlerThread handlerThread = new HandlerThread("handler_thread");
//在使用HandlerThread的getLooper()方法之前,必须先调用该类的start()方法启动线程
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
Message msg = myHandler.obtainMessage();
//将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象
Bundle b = new Bundle();
b.putInt("age", 20);
b.putString("name", "Jhon");
msg.setData(b);
//发送消息对象
msg.sendToTarget();
}
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
}
public void handleMessage(Message msg){
Bundle b = msg.getData();
int age = b.getInt("age");
String name = b.getString("name");
Log.i(SWORD,"age--"+age+" name---"+name);
Log.i(SWORD,"handlerId"+Thread.currentThread().getId());
Log.i(SWORD,"handlerMessage");
}
}
}
运行并查看日志输出结果:
相关文章推荐
- android获取系统时间
- Android新控件Snackbar的介绍以及使用
- 【Android归纳】基于XListView的下拉刷新、上拉加载更多的控件分析
- Android-Mac电脑如何进行APK反编译-第二季
- android 堆内存的一些小知识
- 收集android崩溃信息
- gridview控制显示行数
- Android开发总结笔记 AsyncTask 5-2
- Android lollipop 5.1 读取SIM卡联系人
- 关于android获取sd卡路径的方法
- Android 插件化 动态升级
- android activity与view的联系--window
- Android中自定义View的MeasureSpec使用
- Android 关于expandableListView childrenView 点击改变颜色
- Android使用Xutils在Entity填充数据
- Android 屏幕适配方案
- 《疯狂Android讲义》
- 教你搞定Android自定义ViewGroup
- vlc_for_android 编译安装(未完成)
- android xml界面布局特殊属性