Android 消息机制原理
2017-06-02
概述 Android 的 UI 控件不是线程安全的,因此规定访问 UI 必须在主线程(即 UI 线程)中进行。ViewRootImpl 的checkThread()方法对 UI 操作进行验证,如果在后台线程中访问 UI,程序就会抛出异常。 但主线程中不适合进行耗时操作,因为这样会导致 ANR,所以耗时操作应在后台线程中进行。执行完成后,再使用 Handler 切换到主线程进行 UI 操作。 为什么 UI 控件不设计成线程安全的呢?一是避免访问逻辑变复杂,二是避免效率低下。 Handler 是 Android 消息机制的上层接口,通过它可以将一个任务切换到 Handler 所在的线程中执行。Handler 的运行需要 MessageQueue 和 Looper 支撑。MessageQueue 维护了一个 Message 链表,以队列的逻辑结构向 Handler 和 Looper 提供接口,Looper 中维护了一个 MessageQueue 类型的消息队列。Handler 将 Message 加入队列,Looper 以无限循环的方式查找队列中是否有需要处理的 Message。 Looper 类中 ThreadLocal 类型的静态变量sThreadLocal,用于为当前线程保存和获取 Looper(ThreadLocal 用于为当前线程保存变量,此变量只能被当前线程访问,其它线程无法访问)。 后台线程默认是没有初始化 Looper 的。创建 Handler 实例时,如果没有事先为当前线程创建 Looper,或没有使用特定的构造方法指定 Looper 对象,就会抛出异常。后台线程中一般使用Looper.prepare()方法为当前线程创建一个 Looper。 主线程,即 ActivityThread,其创建时就会初始化 Looper,因此主线程中默认可以使用 Handler。 Handler 创建完毕后,可使用 post 开头的方法(以下简称 post 方法)发送一个 Runnable,也可使用 send 开头的方法(以下简称 send 方法)发送一个 Message,本质都是将一个 Message 加入 Handler 对应的 Looper 中的消息队列。post 方法本质上是将发送的 Runnable 指定为新建 Message 实例的callback属性,然后再将此 Message 加入队列。Looper 发现有需要处理的 Message,就会调用对应 Handler 的dispatchMessage()方法来处理。因此 Handler 中的业务逻辑就在 Handler 对应的 Looper 所在线程中执行。这也是后台线程能通过主线程中的 Handler 来更新 UI 的原因。 …
单例模式 Singleton Pattern
2017-05-26
许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。单例模式限制只有一个实例存在。 通常单例模式有两种构建方式: 懒汉方式,全局的单例实例在第一次被使用时创建,不试图获取这个实例就不会创建,从而实现了延迟加载 优点:类加载快,可调用动态数据(例如 Android 中的 Context 对象) 缺点:对象获取慢,多线程环境下需要考虑线程安全问题 饿汉方式,全局的单例实例在类装载时构建,在装载类时就初始化这个实例,而不是获取时才创建 优点:对象获取快,天生线程安全 缺点:类加载慢,无法调用动态数据 …
Java 设计模式
2017-05-26