目录
在项目中,使用Handler是比较多的,延迟处理信息啊,或者跨线程刷新UI界面啊等.用大家都会用,但要用好,或许只能多看看源码和跟大牛们学习学习了.
Handler.java,Looper.java,Message.java,MessageQueue.java这几个类主要是在/frameworks/base/core/java/android/os目录中.
各类的功能简介
- Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage)
- Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者
- Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息
- MessageQueue:消息队列的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next)
记住以上几个类都是相关联的,总有"千丝万缕"的关系!
项目中常用实例
实例一: 主线程中使用Handler(部分代码)
private Handler mHandler= new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//处理消息
}
};
@Override
protected void onDestroy() {
super.onDestroy();
//移除所有callback和message,并把mHandler设置为null
if(null!=mHandler){
mHandler.removeCallbacksAndMessages(null);
mHandler= null;
}
}
只要写过Android代码都朋友,都是很熟悉以上代码的.
上面我们说过Handler,Looper,Message都是有着"千丝万缕"的关系,但眼睛雪亮的朋友会发现,上面代码都没有发现Looper和MessageQueue呢.
恩,别急,看完所有实例,我们再解释.
实例二:子线程中使用Handler(部分代码)
//代码片段1:我们直接定义一个Handler
private class MyThread extends Thread{
private Handler myHandler = null;
@Override
public void run() {
super.run();
myHandler =new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//to do something
}
};
}
}
以上代码会报如下错误:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
我们继续
//代码片段2,多次调用Looper.prepare()
private class MyThread extends Thread{
@Override
public void run() {
super.run();
//多次调用会抛出异常
Looper.prepare();
Looper.prepare();
}
}
运行代码片段2,就会抛出如下异常:java.lang.RuntimeException: Only one Looper may be created per thread
也就是说,一个线程中只运行运行一次Looper.prepare(),否则抛出异常,至于原因我们后面分析.
我们继续
//代码片段3,加Looper.prepare()和Looper.loop()
private class MyThread extends Thread{
@Override
public void run() {
super.run();
//初始化
Looper.prepare();
myHandler =new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//to do something
Log.d(TAG, "----handleMessage-----what:"+ msg.what);
}
};
myHandler.sendEmptyMessageDelayed(MSG_NOTIFY_END, 1000);
//循环
Looper.loop();
//这下面的代码永远不会执行
}
}
如果加上了Looper.prepare()和Looper.loop(),程序不会报错,同时myHandler可以接收并处理发送来的消息!
如果我们只是加Looper.prepare(),此时myHandler是无法接收到消息的(有兴趣的朋友可以把Looper.loop注释了试试看)
可以说Looper.prepare()和Looper.loop()是必须配套使用的,缺一不可!
接下来揭开迷雾,请继续
我们在主线程使用Handler时并没有发现Looper.prepare()和Looper.loop(),这个怎么回事?
其实Android在创建主线程时就把Looper.prepare()和Looper.loop()初始化好了,这个需要看源码,如下:
base\core\java\android\app\ActivityThread.java
ActivityThread.java 的main()
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
AndroidKeyStoreProvider.install();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper(); //[这里调用的是Looper.prepareMainLooper()]
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop(); //[Looper开始循环,下面代码一般会不执行的]
throw new RuntimeException("Main thread loop unexpectedly exited");
}
至于Android什么时候会执行ActivityThread.java中的main(),我们以后专门分析!
base\core\java\android\os\Looper.java
1.Looper.java中的prepareMainLooper()
public static void prepareMainLooper() {
prepare(false); //[这里最终调用的还是Looper.prepare()]
//[这里进行了sMainLooper是否为null判断,如果多次调用,这里会抛出异常]
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
从上面"throw new IllegalStateException("The main Looper has already been prepared.");"告诉我们Looper.prepareMainLooper()只允许调用一次!
2.Looper.java中的prepare()
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
Looper中有两个prepare方法,一个公开的,一个私有的,最终执行的都是prepare(boolean quitAllowed)
我们会发现,prepare中会判断sThreadLocal中是否存在同一个Looper,如果存在,就抛出"Only one Looper may be created per thread"异常.
3.Looper.java出示Looper(boolean quitAllowed)
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper在初始化时创建了MessageQueue,同时获取当前的线程.
小结一会儿
- 从上面中我们可以只带Looper.prepare()就是对Looper()的初始化,同时保存在sThreadLocal(至于此人是谁,我们后续讲解)中.
- 主线程和子线程中初始化的Looper时的区别是,主线程中的MessageQueue(boolean quitAllowed)是为false,既不允许退出,而子线程是允许退出的.
好了,目前就分析到这,预知后事如何,请听下回讲解.谢谢.
在这里还是推荐我的读书导航网址大全,读书是一种生活方式:http://www.91es.com/index.html