1.主线程的looper.loop()是个死循环,为什么ui线程不会出现anr。
首先,其次在ActivityThread中如果looper执行结束了,应用程序的主线程就结束。
anr核心也是通过looper处理超时消息来实现的。
就那广播的10s未执行完,然后出现anr这来举例。在发送广播的时候会发送一条广播消息,和一条延迟的广播超时消息,如果广播执行完成就从messagequeue中删除掉超时消息,此时程序正常运行。如果广播延迟消息发送就会执行anr相关代码。
具体可以看这个博客:https://blog.csdn.net/jackwang_dev/article/details/78287651
2.handler线程切换到主线程的原理是怎样?
核心思想就是通过共享变量进行消息处理。
主线程中的Looper.loop()方法是一个死循环,保证了程序不退出,能够一直从MessageQueue中取消息并处理(这都是发生在主线程)。在其他线程中只要能够向MessageQueue中添加消息(发生在其他线程),主线程在循环过程中取到消息做对应的处理,这个处理动作可以看成一个函数,主线程接到消息之后取执行对应的函数,那么这个函数执行的线程就是主线程了。
接下来看看我做的一个模拟,通过共享变量queue来切换线程执行。
package com.company;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
public class Test {
public static void main(String[] args) {
FHander hander = new FHander();
hander.loop();
new Thread(new Runnable() {
@Override
public void run() {
hander.addMsage(Thread.currentThread().getName());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
hander.addMsage("delay200 "+Thread.currentThread().getName());
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
hander.addMsage(Thread.currentThread().getName());
}
},"线程2").start();
new Thread(new Runnable() {
@Override
public void run() {
hander.addMsage(Thread.currentThread().getName());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
hander.addMsage("delay300 "+Thread.currentThread().getName());
}
},"线程3").start();
}
}
class FHander{
public static final Queue<String> queue = new ArrayBlockingQueue<String>(100);
private boolean startLoop = false;
public void loop(){
if(startLoop){
throw new RuntimeException("消息循环只开启一次就行");
}
startLoop = true;
//如果这里不加线程,main方法就会卡死,在ActivityThrad中不用加线程,因为需要app不退出,
new Thread(new Runnable() {
@Override
public void run() {
while(true){
if(!queue.isEmpty()){
String msg = queue.poll();
System.out.println("处理消息 thread = "+Thread.currentThread().getName()+" msg = "+msg);
}
}
}
},"MainThread").start();
}
public void addMsage(String s){
System.out.println("添加消息线程为"+Thread.currentThread().getName());
queue.add(s);
}
}
执行结果是
添加消息线程为线程1
添加消息线程为线程2
处理消息 thread = MainThread msg = 线程1
处理消息 thread = MainThread msg = 线程2
添加消息线程为线程3
处理消息 thread = MainThread msg = 线程3
添加消息线程为线程1
处理消息 thread = MainThread msg = delay200 线程1
添加消息线程为线程3
处理消息 thread = MainThread msg = delay300 线程3
代码简单的一皮,就是主线程开启死循环从queue中取数据然后做处理。然后开启其他线程来向queue中加数据。每加一个数字,就能切换到主线程中执行。
以上就是handler切换线程代码执行的原理。
3.WindowSession的作用是什么?
windowSession是一个binder,它是主线程和WMS(SystemService)沟通的binder,适用它可以在这两进程之间传递数据,比如windoSession.add()向WMS中添加window,另外一方面WMS处理事件消息的时候会根据消息句柄找到对应的window,传递给View。