研究非常透彻
线程间通信机制
发送两种类型的数据
1.sendmessage
2.post(runnable)
2.handler机制牵涉到几个重要的类?
message,messagequeue,looper,handler,handlerthread(intentservice),activitythread(入口类)
threadlocal
7个类作用,使用场景学会,handler就会了
队列,算法是什么呢
底层的数据结构:链表结构
activitythread:程序入口类,主线程的,里面会初始化主线程的looper,looper是threadlocal这个类存储looper,
(1)ThreadLocal适用于某些数据以线程为作用域并且不同线程具有不同数据副本的场景。
大白话,threadlocal就是维护looper、的,保证每个线程的looper相互独立,确保每个线程的looper绑定当前线程
Message message = new Message();//第一种方式
Message message2 = Message.obtain();//第二种方式
Message message1 = handler.obtainMessage();//第三种方式
message.obj = new String();
message.what = 1;
message.arg1 = 2;
message.arg2 = 3;
Only one Looper may be created per thread
什么意思:1.每个线程只有一个looper 2.线程和lopper一一对应的绑定关系
徐庆臣 1861299102 2018/7/24 12:04:36
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
这行代码的意思,来同学们总结一下:
实例化looper的时候,构建messagequeue对象,意味着:一个looper对象维护一个唯一的messagequeue对象
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
1.把当前线程的msgqueue对象初始化
返回一个方法:enqueueMessage,故名思义:入队
分包,分层,分模块,分方法(逻辑更清晰,功能更简洁,更容易维护)
入队的时候,为什么要加锁
锁的作用:保证只有一个线程访问对象
总结,入队注意:1.同步锁机制 2.通过链表数据结构维护数据 也就是:先进先出的原则
169.254.49.118:80
java 轮询
handler是如何做到切换线程
loop()方法是一个死循环
你认为运行在哪个线程
activity、几秒钟:5秒
广播接收器:10秒
service:20秒
总结:Looer.loop()方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常。
安淇撤回了一条消息
https://blog.youkuaiyun.com/vapingzi/article/details/79395012
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。
但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。
HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。
为什么Looper.loop()死循环不会导致ANR
为什么loop这个死循环会在主线程执行,不会ANR么?
答:最开始Android的入口ActivityThread里面的main方法,里面有一个巨大的Handler,然后会创建一个主线程的looper对象,这也是为什么直接在主线程拿Handler就有Looper的原因,在其他线程是要自己Looper.prepare()的。
其实整个Android就是在一个Looper的loop循环的,整个Android的一切都是以Handler机制进行的,即只要有代码执行都是通过Handler来执行的,而所谓ANR便是Looper.loop没有得到及时处理,一旦没有消息,Linux的epoll机制则会通过管道写文件描述符的方式来对主线程进行唤醒与沉睡,Android里调用了linux层的代码实现在适当时会睡眠主线程。
真正会卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。
ActivityThread的main方法主要作用就是做消息循环,一旦退出消息循环,主线程运行完毕,那么你的应用也就退出了。
Android是事件驱动的,在Loop.loop()中不断接收事件、处理事件,而Activity的生命周期都依靠于主线程的Loop.loop()来调度,所以可想而知它的存活周期和Activity也是一致的。当没有事件需要处理时,主线程就会阻塞;当子线程往消息队列发送消息,并且往管道文件写数据时,主线程就被唤醒。
主线程在没有事件需要处理的时候就是处于阻塞的状态。想让主线程活动起来一般有两种方式:
第一种是系统唤醒主线程,并且将点击事件传递给主线程;
第二种是其他线程使用Handler向MessageQueue中存放了一条消息,导致loop被唤醒继续执行。
主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。
总结: Looer.loop()方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常。