http://www.wangzhanyun.net/index/2011/12/30/cant-create-handler-inside-thread-that-has-not-called-looper-prepare/
问题:
最近在做一个使用SIP通话的客户端。在程序启动的时候要启动蓝牙设备,以连接蓝牙耳机等。
当在一个Thread中调用蓝牙初始化的方法时出现如下的错误:
|
public
static
void
init() {
if
(ba ==
null
) {
ba = BluetoothAdapter.getDefaultAdapter();
am = (AudioManager) Receiver.mContext.getSystemService(
Context.AUDIO_SERVICE);
}
}
|
Error Code:
12-30 11:48:21.577: W/System.err(25134): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
12-30 11:48:21.639: W/System.err(25134): at android.os.Handler.(Handler.java:121)
12-30 11:48:21.639: W/System.err(25134): at android.bluetooth.BluetoothAdapter$1.(BluetoothAdapter.java:853)
12-30 11:48:21.639: W/System.err(25134): at android.bluetooth.BluetoothAdapter.(BluetoothAdapter.java:852)
12-30 11:48:21.639: W/System.err(25134): at android.bluetooth.BluetoothAdapter.getDefaultAdapter(BluetoothAdapter.java:324)
12-30 11:48:21.639: W/System.err(25134): at org.xxxx.media.Bluetooth.init(Bluetooth.java:43)
分析:
报的是一个Android Looper的错误,从字面意思上看是没有调用Looper.prepare()方法。
1. Looper是什么?
Looper又是什么呢? ,其实Android中每一个Thread都跟着一个Looper,Looper可以帮助Thread维护一个消息队列。默认的Thread是没有Looper机制的,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。
|
class
LooperThread
extends
Thread {
public
Handler mHandler;
public
void
run() {
Looper.prepare();
mHandler =
new
Handler() {
public
void
handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
|
2. 为什么在Thread内调用初始化Bluetooth的方法需要调用Looper.prepare()?
从现象上来看调用ba = BluetoothAdapter.getDefaultAdapter();应该在主线程中进行调用,不应该在工作线程中。
在工作线程中调用可能会由于没有消息队列的管理导致线程不同步。
3. 使用Handler是否可以解决问题,怎么使用?
在主线程中创建Handler,另外一个线程怎样把消息放入主线程的消息队列呢?
答案是通过Handle对象,只要Handler对象以主线程的Looper创建,那么调用Handler的sendMessage等接口,将会把消息放入队列都将是放入主线程的消息队列。并且将会在Handler主线程中调用该handler的handleMessage接口来处理消息。
解决问题:
在Application创建一个Handler的实例,实现handleMessage接口。
在Thread中可以获取Application的实例,调用Application里面的一个方法用Handler send Message的方式执行蓝牙设备初始化的代码。
|
/*
* in Thread
*/
final
App app = (App)mApplication;
app.startSIPEngine();
|
|
/*
* in Application
*/
class
App
extends
Application{
private
Handler mApplicationHandler =
new
Handler(){
@Override
public
void
handleMessage(Message msg) {
//TODO do some native service register work
BluetoothHelper.init();
}
};
public
void
startBluetooth(){
mApplicationHandler.sendMessage(
new
Message());
}
}
|
参考问题:
Can’t create handler inside thread that has not called Looper.prepare()
深入理解Android消息处理系统——Looper、Handler、Thread