您的位置:首页 > 移动开发 > Android开发

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

}

}

}

运行并查看日志输出结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: