目录
什么是Handler
Handler是Android给我们提供的一套消息处理机制,平常我们经常用Handler就是将子线程的数据传递给主线程,其实,熟悉Handler原理之后我们知道,Handler不仅仅能将子线程的数据传递给主线程,它能实现任意两个线程的数据传递。
Handler的使用方法
首先看一下Handler最常规的使用方式:
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MESSAGE_WHAT:
Log.d(TAG, "main thread receiver message: " + ((String) msg.obj));
break;
}
}
};
private void sendMessageToMainThreadByWorkThread() {
new Thread(){
@Override
public void run() {
Message message = mHandler.obtainMessage(MESSAGE_WHAT);
message.obj = "你好,我是子线程";
mHandler.sendMessage(message);
}
}.start();
}
/*
* 通常我们在主线程中创建一个Handler,
* 然后重写该Handler的handlerMessage方法,可以看到该方法传入了一个参数Message,
* 该参数就是我们从其他线程传递过来的信息。
*
* 我们在来看下子线程中如何传递的信息,子线程通过Handler的obtainMessage()方法获取到一个Message实例,
* 我们来看看Message的几个属性:
* Message.what------------------>用来标识信息的int值,通过该值主线程能判断出来自不同地方的信息来源
* Message.arg1/Message.arg2----->Message初始定义的用来传递int类型值的两个变量
* Message.obj------------------->用来传递任何实例化对象
* 最后通过sendMessage将Message发送出去。
* Handler所在的线程通过handlerMessage方法就能收到具体的信息了,如何判断信息的来源呢?可以通过what值来判断.
*/
首先我们在主线程中创建一个Handler,
然后重写该Handler的handlerMessage方法,可以看到该方法传入了一个参数Message,
该参数就是我们从其他线程传递过来的信息。
子线程:
子线程通过Handler的obtainMessage()方法获取到一个Message实例,向Message中可以传入任何实例化对象(需要发送的内容)最后通过sendMessage将Message发送出去。
Handler所在的线程通过handlerMessage方法就能收到具体的信息了.
上面提到Handler不仅仅是能过将子线程的数据发送给主线程,它适用于任意两个线程之间的通信。
下面我们来看下两个子线程之间如何进行通信的。
就按照正常逻辑在一个线程创建Handler,另外一个线程通过持有该Handler的引用调用sendMessage发送消息就可以了!
接下来通过代码实现以下:
private Handler handler;
private void handlerDemoByTwoWorkThread() {
Thread hanMeiMeiThread = new Thread() {
@Override
public void run() {
// Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "hanMeiMei receiver message: " + ((String) msg.obj));
Toast.makeText(MainActivity.this, ((String) msg.obj), Toast.LENGTH_SHORT).show();
}
};
// Looper.loop();
}
};
Thread liLeiThread = new Thread() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = handler.obtainMessage();
message.obj = "Hi MeiMei";
handler.sendMessage(message);
}
};
hanMeiMeiThread.setName("韩梅梅 Thread");
hanMeiMeiThread.start();
liLeiThread.setName("李雷 Thread");
liLeiThread.start();
/*
* 搞定,我们创建了两个Thread,liLeiThread和hanMeiMeiThread两个线程,很熟悉的名字啊!
* 跟之前的代码没太大区别hanMeiMeiThread创建了Handler,liLeiThread通过Handler发送了消息。
* 只不过此处我们只发送一个消息,所以没有使用what来进行标记
* 运行看看,我们的李雷能拨通梅梅吗?
* 啊哦,出错了
* 05-13 17:08:17.709 20673-20739/? E/AndroidRuntime: FATAL EXCEPTION: 韩梅梅 Thread
Process: design.wang.com.designpatterns, PID: 20673
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
*Can't create handler inside thread that has not called Looper.prepare()
* -----------》它说我们创建的handler没有调用Looper.prepare();
* 好的,我们在实例化Handler之前调用下该方法,看一下。加上是不是没有报错了呢。
* 等等,虽然没有报错,但是hanMeiMeiThread也没有接到消息啊,消息呢?别急。
* 我们在Handler实例化之后加上Looper.loop();看一看,运行一下,是不是收到消息了呢。
* 这是为什么呢?
* 接下来我们就去看看Handler是怎么实现的发消息呢,弄清楚了原理,这里的原因也就明白了。
*/
}
通过代码实现后运行程序,会发现抛出异常了,
Can't create handler inside thread that has not called Looper.prepare()
提示我们创建的handler没有调用Looper.prepare();
那么我们在实例化Handler之前调用下该方法,看一下还会不会报错.
运行后发现并没有报错,但是发出去的消息并没有被接收到,
在Handler实例化之后加上Looper.loop();看一看,运行一下,是不是收到消息了呢。
既然加上了Looper.loop();就可以收到消息了,那是不是就可以说Looper.loop()就是用来发送消息的呢?
我们可以去源码中看一下我们抛出的异常的原因和为什么在子线程中要多了Looper,并且验证下我们的猜想.
首先我们来看下,为什么在子线程里实例化的时候不调用Looper.prepare()就会报错呢?
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
我们找到Handler构造函数里抛出上文异常的地方,可以看到,是由于mLooper对象为空才抛出的该异常。