Android的Handler知识点

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.post
Handler.postDealy
View.post等都是是最终会调用到queue.enqueueMessage
sendMessageDelayed(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中规定必须在主线程更新UI
Android方案:在页面刷新时通过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管道写端写入数据来唤醒主线程工作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

quchen528

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值