有一定操作系统基础知识的同学都知道,线程可以称为轻量的进程,具有极其有限的一部分独立空间,能够独立执行一定的任务,但是创建销毁的空间时间资源都要远低于进程。
在安卓中,一般来说一个app运行在一个进程之上(暂时不考虑native方法fork出的子进程),而进入这个进程我们最先接触到的线程就是UI线程(主线程)。主线程负责向UI组件分发事件,包括绘制点击等,这个线程资源很稀缺,一旦进行了过多的耗时操作就可能出现anr。
我们都知道在cpu层面,所有的线程都是在cpu上按照一个一个时间片执行的,一个时间片可能会有数个毫秒。当然线程之间会有不同的优先级和调度方式,但是线程过多导致的切换花销也是没必要的。比如只是进行一个简单的网络请求或者加载资源,完全没必要单独创建一个线程。这里就可以使用线程池或者自定义一个线程进行处理,这个线程或者几个线程可以长期存活(也相当于自定义线程池)。
当然线程池的在整个大型的app项目中使用比较繁琐,而不断的new Thread又很耗费资源,这里就搬出我们强大的handler。
从我们开发者的角度来说,Handler是Android消息机制的上层接口,通过handler,可以将一个任务切换到handler所在的线程中执行,我们通常使用handler来更新UI,但更新UI仅仅是的使用场景之一,handler并不是仅仅用来更新UI。它也可以运行在异步线程上,执行耗时的任务。
至于handler的具体使用和机制这里就不具体讲解了各种文章有很多。
这里我们需要澄清一个容易绕晕的概念,在安卓中,每个线程都会持有一个looper,负责从消息队列中取出消息进行执行。一个线程只能有一个looper,但是一个looper可以服务于多个线程。也就是线程本身的looper负责从自己的任务队列中取出任务进行执行,mainlopper持有者即为主线程,可以通过
Looper.myLooper() == Looper.getMainLooper()
判断当前是否在主线程
我们就可以在主线程创建一个handler,构造方法中传入mainlopper,在handleMessage前判断
if (Looper.myLooper() != Looper.getMainLooper()) {
return;
}
那么抛到这个handler执行的任务都会在主线程进行。
那么异步线程也是同理的
自定义一个子线程,在线程run的时候
Looper.prepare();
// 定义handler等操作
Looper.loop();
我们的线程handler就有了自己的looper,即运行在异步线程上。而抛到这里的代码块都会执行在异步线程上,一些费时的操作都可以在这里执行,包括后台加载资源等。
这样一个单例类就可以管理主线程和异步线程,并且很方便的进行线程的切换和管理。