您的位置:首页 > 运维架构

为什么在主线程的Looper.looper死循环不会卡死

2017-05-02 17:57 661 查看
public static void main(String[] args) {
.... //创建Looper和MessageQueue对象,用于处理主线程的消息
Looper.prepareMainLooper();
//创建ActivityThread对象
//建立Binder通道 (创建新线程)
thread.attach(false); Looper.loop(); //消息循环运行
throw new RuntimeException("Main thread loop unexpectedly exited");
}
1
2
3
4
5
6
7
8


1
2
3
4
5
6
7
8
[/code]

我们看looper.loop()的源码

/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
Looper me = myLooper();//获取当前looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}//如果为空,则抛异常
MessageQueue queue = me.mQueue;//把当前looper的queue赋值给局部变量queue

// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();//确保当前线程属于当前进程,并且记录真实的token。
final long ident = Binder.clearCallingIdentity();

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.退出消息的标示就是target为空
return;
}

long wallStart = 0;
long threadStart = 0;

// This must be in a local variable, in case a UI event sets the logger 一个局部变量,为ui事件设置log记录。
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
//handler处理消息
msg.target.dispatchMessage(msg);

if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;

logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}

// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.确保调用过程中线程没有被销毁
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//处理完成后,调用Message.recycle()将其放入Message Pool中。
msg.recycle();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
[/code]

那么知乎上一个大神这么说 隔开隔开

对于线程既然是一段可执行的代码,当可执行代码执行完成后,线程生命周期便该终止了,线程退出。而对于主线程,我们是绝不希望会被运行一段时间,自己就退出,那么如何保证能一直存活呢?简单做法就是可执行代码是能一直执行下去的,死循环便能保证不会被退出,例如,binder线程也是采用死循环的方法,通过循环方式不同与Binder驱动进行读写操作,当然并非简单地死循环,无消息时会休眠。但这里可能又引发了另一个问题,既然是死循环又如何去处理其他事务呢?通过创建新线程的方式。

真正会卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。

作者:Gityuan

链接:https://www.zhihu.com/question/34652589/answer/90344494

来源:知乎

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

隔开隔开

这是一个大神说的 乍看起来好像有点不懂

那么我来说说我的理解

Looper.loop()中的for循环会让当前线程阻塞,不是卡死,这个和操作系统有关。如果你在主线程操作,如activity生命周期onCreate、主线程的handler,实际上是都是通过handler发消息的,消息会在刚才的for循环中处理,这个消息会唤醒线程,如果你在onCreate(),onResume()里面处理耗时操作,那么下一次的比如用户的点击事件不能处理了,那就会卡死了

(function () {('pre.prettyprint code').each(function () {
var lines = (this).text().split(′\n′).length;varnumbering = $('').addClass('pre-numbering').hide();
(this).addClass(′has−numbering′).parent().append(numbering);
for (i = 1; i
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: