先看看一段代码:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();
很遗憾,上面的代码会报错:
AndroidRuntime(2545): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
在看看这Log是在源码的什么地方打印的
/**
* Default constructor associates this handler with the queue for the
* current thread.
*
* If there isn't one, this handler won't be able to receive messages.
*/
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) { //当mLooper为null时就会报这个异常
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
这下我们知道了,在mLooper == null时就会报错,所以需要looper.prepare().
正确的代码写法:
new Thread(new Runnable() {
public void run() {
Looper.prepare();
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
Looper.loop();
};
}).start();
可能你会有一个疑问,问什么在UI线程中就不需要Looper.prepare(); Looper.loop();
其实UI线程也是一个线程,在主线程–>prepareMainLooper()(内部调用prepare() ,去实例化Looper,Looper实例化同时创建了messagequeue,一一对应关系)–>主线程中的handler获取当前线程的Looper–>三者关联
所以在UI线程中我们不需要调用Looper.prepare(); Looper.loop();
如果还是不想写Looper.prepare(); Looper.loop(); 那么推荐一个类HandlerThread,查看源码会发现内部已经实现了Looper.prepare(); Looper.loop();
常用api
//消息
Message message = Message.obtain();
//发送消息
new Handler().sendMessage(message);
//延时1s发送消息
new Handler().sendMessageDelayed(message, 1000);
//发送带标记的消息(内部创建了message,并设置msg.what = 0x1)
new Handler().sendEmptyMessage(0x1);
//延时1s发送带标记的消息
new Handler().sendEmptyMessageDelayed(0x1, 1000);
//延时1秒发送消息(第二个参数为:相对系统开机时间的绝对时间,而SystemClock.uptimeMillis()是当前开机时间)
new Handler().sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000);
//避免内存泄露的方法:
//移除标记为0x1的消息
new Handler().removeMessages(0x1);
//移除回调的消息
new Handler().removeCallbacks(Runnable);
//移除回调和所有message
new Handler().removeCallbacksAndMessages(null);