Android异步处理技术(一)
移动应用的开发要求我们正确的处理好主线程和子线程之间的关系,耗时的操作应该放到子线程中,避免阻塞主线程,导致ANR。异步处理技术是提高应用性能,解决主线程和子线程之间通信问题的关键。
在Android 中,异步处理技术有很多种,常见的有Thread,AsyncTask,Handler&Looper,Executors等,在实际项目中,我们需要根据具体业务需求进行选择,一个完整的异步处理技术继承树如图

Thread
线程是java语言的一个概念,它是实际执行任务的基本单元,Thread是Android 中异步处理的基础,创建线程有两种方法
1 继承Thread 类并重写run方法

2 实现Runnable 接口并实现run方法

Android 应用中各种类型的线程本质上都基于Linux系统的pthreads,在应用层可以分为三种类型的线程。
1 主线程:主线程也成为UI线程,随着应用启动而启动,主线程用来运行Android 组件,同时刷新屏幕上的UI元素,Android 系统如果检测到非主线程更新UI组件,那么就会抛出CalledFromWrongThreadException异常 ,只有主线程才能操作UI,是因为Android 的UI工具包不是线程安全的,主线程中创建的Handler 会顺序执行接受到的消息,包括从其他线程发送的消息,因此,如果消息队列中前面的消息没有很快执行完,那么它可能会阻塞队列中的其他消息的及时处理。
2 Binder线程:Binder线程用于不用进程之间线程的通信,每个进程都维护了一个线程池,用来处理其他进程中线程发送的消息,这些进程包括系统服务,Intents,ContentProviders和Service等,在大部分情况下,应用不需要关心Binder线程,因为系统会优先将请求转换为使用主线程,一个典型的需要使用Binder线程的场景是英语提供一个给其他进程通过AIDL接口绑定的Service。
3 后台线程:在应用中显式创建的线程都是后台线程,也就是当刚创建处理时,这些线程的执行体是空的,需要手动添加任务,在Linux系统层面,主线程和后台线程是一样的,在Android框架中,通过WindowManager 赋予了主线程只能处理UI更新以及后台线程不能直接操作UI的限制
HandlerThread
HandlerThread是一个集成了Looper和MessageQueue的线程,当启动HandlerThread时,会同时生成Looper和MessageQueue,然后等待消息进行处理,它的run方法源码如下

使用HandlerThread的好处是开发者不需要自己去创建和尾狐Looper,它的用法和普通线程一样

HandlerThread中只有一个消息队列,队列中的消息是顺序执行的,因此是线程安全的,当然吞吐量自然受到一定的影响,队列中的任务可能会被前面没有执行完的任务阻塞,HandlerThread的内部机制确保了在创建Looper和发生消息之前不存在静态条件,这个是通过将HandlerThreqad.getLooper()实现为一个阻塞操作实现的,只有当HandlerThread准备好接受消息之后才会返回

如果具体业务要求在HandlerThread开始接受消息之前要进行某些初始化操作的话,可以重写HandlerThread的onLooperPrepared函数,例如可以在这个函数中创建与HandlerThread关联的Handler实例,这同时也可以对外隐藏我们的Handler实例
