android 中的线程基于 linux 的线程,当我们启动一个 App 的时候,Android系统会启动一个Linux Process,该 Process 包含一个 Thread,称为UI Thread或Main Thread。
通过示例来了解 android 中的线程,创建一个新的 Android 项目。在 activity 中添加两个 button (启动和停止线程)和 textview,button 用于控制启动和停止线程,textview用于接收线程返回值,便于查看线程是如何更新视图,后台线程或叫做工作线程是如何与主线程进行通讯的。现在做一个最简单的示例,代码如下。这里打印的线程为主线程的 id。
运行一段时间,我们的应用就崩溃了,这是应打印阻塞了 UI 线程中其他逻辑的执行,从而导致界面卡顿。如果卡顿时间超过5秒,系统就会报 ANR 错误。这样来看,要执行耗时的操作的话,我们就需要另起线程执行。
然后让代码运行在一个新创建的线程,代码如下,再看一看效果,
好了!我们已经成功解决上一个问题,接下来要做的事。是如何把处理结果传回到主线程以更新 UI。
我们通过 handler 对象,将在新线程中执行的结果发送回主线程中来执行。
总结一下
Android 是如何处理线程间通信的,看一看上图,在主线程会循环地执行一个一个的任务。将 Message 或 Runnable 对象看成一个一个任务,这些对象(任务)在线程间传递数据。MessageQueque: 消息队列,是 Message 和 Runnable 的容器,他们都是按一定顺序存放在消息队列中(任务可以按照一定优先级进行执行),依次被处理 Looper :负责Message 和 Runnable 对象,分发给相应的 Handler 对象。Hander 即是 Message 和 Runnable 对象的来源,也就是说他将对象发送给 MessageQueque 同时也是 Looper 对象的接收器,Looper 会把 Message 和 Runnable 发送给 Handler。并且在从 Looper 接受后执行 Message 和 Runnable 发送操作在发送线程中完成,而执行操作在接收线程中完成,来实现不同线程的通讯。
AsyncTask是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。
AsyncTask 不是线程框架,只是一个用于工作线程和主线程之间通讯的通讯类。其中 doInBackground 是抽象方法,doPreExecute,onProgressUpdate, onPostExecute, onCancelled 还好理解,大家可以自己做些功课
这里重点说一下 Executor 每次 AsyncTask 要被执行时,都必须提供一个 Executor 对象。启动 AsyncTask 有三种方式
1. execute(params): 将任务添加到 SERIAL_EXECUTOR 队列中。
2. execute(Runnable) 这是静态方法,用于执行 Runnable 对象
3. executeOnExecutor(Executor, Params) 通过此方法可以指定 Executor。
AsyncTask通过一个阻塞队列BlockingQuery<Runnable>存储待执行的任务,利用静态线程池THREAD_POOL_EXECUTOR提供一定数量的线程,默认128个。在Android 3.0以前,默认采取的是并行任务执行器,3.0以后改成了默认采用串行任务执行器,通过静态串行任务执行器SERIAL_EXECUTOR控制任务串行执行,循环取出任务交给THREAD_POOL_EXECUTOR中的线程执行,执行完一个,再执行下一个。
可以尝试自己来实现一个 looper 和 Handler。我们在 Thread.run() 中调用静态方法 Looper.prepare() 来定义一个 Looper 对象,创建一个MessageQueue(消息队列),为了 Looper 分发 Message 和 Runnable 给 Handler。
创建一个线程,然后任务发送到消息队列messageQueue
我们来将任务发送给 Runnable 对象,工作进程中执行完的任务,返回到主线程中来更新 UI。
今天到这里吧