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

Android Handler 和 Looper 的研究

2013-06-07 16:30 411 查看
// 多线程 Looper, Handler, 的确验证了handleMessage()跑在了创建 Handler 的线程之内
private void testLooper() {
class MyHandlerThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
Logger.showLog("loopThread --> enter");
Looper.prepare();
Looper.loop(); // 如果不调用, Handler 不起作用
// Handler tHandler = new Handler(){ // 线程内直接创建,会挂掉,log显示未调用 Looper.prepare();
//
// @Override
// public void handleMessage(Message msg) {
// // TODO Auto-generated method stub
// if (msg.what == 1000) {
// TestLog.showLog("I have received message 1000");
// }
// super.handleMessage(msg);
// }
// };
// tHandler.sendEmptyMessage(1000);
Logger.showLog("loopThread --> finish");
}

public Looper getLooper() {
return Looper.myLooper();
}
}
MyHandlerThread loopThread = new MyHandlerThread();
loopThread.start();
Handler tHandler = new Handler(loopThread.getLooper()) { // looper
// 使用辅线程的
// ,确实是把消息跑在了与之相关的线程里

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.what == 1000) {
Logger.showLog("I have received message 1000");
// 让线程阻塞 3s
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (msg.what == 1001) {
Logger.showLog("I have received message 1001");
}
super.handleMessage(msg);
}
};
tHandler.sendEmptyMessage(1000);
tHandler.sendEmptyMessage(1001);
}


结果如下:

01-02 07:50:09.520: D/langren(1248): loopThread --> enter
01-02 07:50:09.530: D/langren(1248): I have received message 1000
01-02 07:50:12.540: D/langren(1248): I have received message 1001
可以看到3s中后才收到第二条消息

在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:

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();
}
}


这个 loop 方法是死循环,当MessageQueue 为空时阻塞。

突然意识到,可能 Activity 最后就是阻塞在这个地方,因为其中

在Handler.java的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。

抽取

Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
在Looper.java的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。


一直死循环等待产生事件

然后尝试在 主线程 UI 线程中创建 默认 Handler

private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1003:
Logger.showLog("I have received message 1003");
// 让线程阻塞 12s
try {
Thread.sleep(12000); // 出现 ANR 了,呵呵
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;

default:
break;
}
};
};


果然出现 ANR 了

ActivityThread 代码中果然如此

public static final void main(String[] args) {
SamplingProfilerIntegration.start();
……
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
……
Looper.loop();
……
thread.detach();
……
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}

下面仔细分析一下这个main方法。

2.Looper.prepareMainLooper();

ActivityThread其实就是我们经常说的UI thread,也就是主线程。我们都知道主线程可以使用Handler进行异步通信,因为主线程中已经创建了Looper,而这个Looper就是在这里创建的。如果其他线程需要使用Handler通信,就要自己去创建Looper。

3. sMainThreadHandler = new Handler();

创建一个Handler。


loop 死循环就是最常见的消息循环机制了。将消息派发到正确的地方执行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: