Looper死循环为什么不会导致线程卡死
1.因为作为一个正常的应用,他应该不能主动去结束自己的生命周期,所有就需要靠Looper死循环去让应用一直保持存活状态2.为什么没有卡死,首先得先理解这里的卡死指的是ANR,ANR是因为应用在一定时间内未做出响应而导致的(InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件、BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒、Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕、ContentProvider Timeout :ContentProvider的publish在10s内没进行完),然而Looper的循环中,当msg.next,主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。
我们使用Message是应该如何创建它
Message.obtain()//---------------------------------public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; // sPool是指向message链表头结点的指针 sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag // 修改标记后才可使用 sPoolSize--; return m; } } return new Message(); }
关于threadLocal,谈谈你的理解
ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。提供线程内部的局部变量,在本线程内随时随地可取,隔离其他线程。threadLocal内有 threadLocalMap保存数据,key为 thread的引用 value为Handler使用Hanlder的postDealy后消息队列会发生什么变化?Handler.postHandler.postDealyView.post等都是是最终会调用到queue.enqueueMessagesendMessageDelayed(getPostMessage(r), delayMillis); -> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);-> enqueueMessage(queue, msg, uptimeMillis) -> queue.enqueueMessage(msg, uptimeMillis)最终都会走到 queue.enqueueMessage 中在其中msg以绝对时间的方式插入到messages链表正确的位置private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
为什么不能在子线程更新UI? Android:为什么子线程不能更新UI - 简书
为什么不能:假如允许多线程更新UI,但是访问UI是没有加锁的,一旦多线程抢占了资源,那么界面将会乱套更新了,体验效果就不言而喻了;所以在Android中规定必须在主线程更新UIAndroid方案:在页面刷新时通过checkThread()判断其是否在主线程,然而checkThread()方法定义在ViewRootImpl中,在activity初始化viewRootImpl后,在invalidate()时,checkThread会抛异常总结:子线程可以在ViewRootImpl还没有被创建之前更新UI;访问UI是没有加对象锁的,在子线程环境下更新UI,会造成不可预期的风险;开发者更新UI一定要在主线程进行操作;注:ViewRootImpl对象是在onResume方法回调之后才创建,那么就说明了为什么在生命周期的onCreate方法里,甚至是onResume方法里都可以实现子线程更新UI,因为此时还没有创建ViewRootImpl对象,并不会进行是否为主线程的判断;
子线程中维护Looper在消息队列无消息的时候处理方案是怎么样的
Looper的循环中,当msg.next,主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生通过往pipe管道写端写入数据来唤醒主线程工作。