Android基础二

100 阅读4分钟

Handler

Handler: 主要负责消息的发送和处理,通过sendMessage()、sendMessageDelayed()等方法把message发送到MessageQueue中,同时在handleMessage回调中拿到Looper从MessageQueue中取出的消息进行处理
Looper: 开启了一个死循环,不断的从MessageQueue中取出消息让Handler处理。一个线程对应一个Looper,同时一个Looper对应一个MessageQueue
MessageQueue: 负责存储消息
Message: 消息本身,负责携带数据

  • Handler的构造函数,会执行mLooper = Looper.myLooper()绑定当前looper、。

  • Handler.sendMessage() 的时候,会设置msg.target = this 然后调用 mLooper.mQueue.enqueueMessage()。\

  • Handler.post(runnable) 其实是msg.callback=runnable,最终也是跟sendMessage() 一样的流程。

  • Looper.prepare()的时候会新建一个Looper并存入sThreadLocal。

  • Looper的构造函数,会执行mQueue = new MessageQueue()。

  • Looper.loop() 不断循环mQueue.next()取出msg,然后调用msg.target.dispatchMessage(msg)。

  • MessageQueue 里有很多native方法,MessageQueue.next()没有消息时会阻塞,MessageQueue.enqueueMessage()收到消息时会唤醒阻塞。

  • 新建Message最好使用Message.obtain(),会优先从缓存池里获取,避免创建对象。

  • 我们在UI线程无需调用Looper.prepare()是因为系统已经帮我们执行过Looper.prepareMainLooper()。

  • 子线程不能直接修改UI,是因为UI的很多方法(比如draw)都不是线程安全的,所以引入Handler和Looper,用队列的形式确保操作UI是同步安全的。

线程池

为什么要使用线程池

  1. 降低资源消耗: 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率
  2. 提高响应速度:任务到达时,无需等待线程创建即可立即执行。
  3. 提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。

原理流程

image.png

  1. 如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
  2. 如果此时线程池中的数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放入缓冲队列。
  3. 如果此时线程池中的数量大于等于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
  4. 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
  5. 当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

总结:处理任务判断的优先级为 核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。核心线程和临时线程的区别就是在线程空闲时间到了keepAliveTime时,临时线程会被回收,如果不设置allowCoreThreadTimeout=true的核心线程则会进入阻塞。

View事件分发

image.png

  • 子View可以通过requestDisallowInterceptTouchEvent方法干预父View的事件分发过程

  • 对于View,如果设置了onTouchListener,那么OnTouchListener方法中的onTouch方法会被回调。onTouch方法返回true,则onTouchEvent方法不会被调用(onClick事件是在onTouchEvent中调用)所以三者优先级是onTouch->onTouchEvent->onClick

  • View 的onTouchEvent 方法默认都会消费掉事件(返回true),除非它是不可点击的(clickable和longClickable同时为false),View的longClickable默认为false,clickable需要区分情况,如Button的clickable默认为true,而TextView的clickable默认为false。

进程的声明周期

什么是进程

Linux 中的程序的一个实例

周期

image.png

进程的保活

进程的重要性层级

image.png

LMK(LowMemoryKiller)

作用
管理所有的进程,根据一定策略来kill进程
基本原理
所有应用进程都是从 zygote 孵化出来的,记录在 AMS 中mLruProcesses 列表中,由 AMS 进行统一管理,AMS 中会根据进程的状态更新进程对应的 oom_adj 值,这个值会通过文件传递到 kernel 中去,kernel 有个低内存回收机制,在内存达到一定阀值时会触发清理 oom_adj 值高的进程腾出更多的内存空间
LMK 杀进程标准
minfree: 存放6个数值,单位内存页面数 ( 一个页面 4kb )
1.前台进程(foreground),2.可见进程(visible),3.次要服务(secondary server),4.后台进程(hidden),5.内容供应节点(content provider),6.空进程(empty)这6类进程进行回收的内存阈值分别为72M,90M,108M,126M,144M,180M
当内存到 180 M的时候会将空进程进行回收,当内存到 144 M 的时候把空进程回收完以后开始对内容供应节点进行回收,并不是所有的内容供应节点都回收,而是通过判断它的优先级进行回收,优先级是用 oom_adj 的值来表示,值越大回收的几率越高
进程保活方案
启动前台服务