当我们启动应用程序时,Android系统会自动启动一个Linux进程。这个进程包含一个UI线程,该线程负责处理许多重要的逻辑,如系统事件处理、用户输入事件、UI绘制、Service和Alarm等。以下是UI线程所包含的逻辑:
Ui Thread 包含的逻辑
在这些逻辑中,我们编写的代码穿插其中,例如对用户触摸事件的检测和响应,以及自定义View的绘制。如果我们在执行耗时操作(如网络请求、数据库读取)时阻塞了UI线程的其他逻辑执行,就会导致页面卡顿。因此,在执行耗时操作时,我们需要使用其他线程来执行。
Android提供了四种常用的多线程操作方式:Handler+Thread、AsyncTask、ThreadPoolExecutor和IntentService。
1. Handler + Thread
Android主线程包含一个消息队列(MessageQueue),通过Handler可以将Message(消息)或Runnable对象推送到该消息队列。每次创建一个新的Handler对象时,它都会绑定到创建它的线程以及该线程的消息队列。
Handler原理图
Handler传递消息有两种方式:Post和SendMessage。对于Handler的Post方法来说,它会将一个Runnable对象推送到消息队列中。在这个Runnable对象的run()方法中,可以编写需要在UI线程上执行的操作。
Handler Post用法示例:
```java
new Handler().post(new Runnable() {
@Override
public void run() {
// 在UI线程上执行的操作
}
});
```
2. AsyncTask
AsyncTask是Android的一个异步类,可以直接继承并使用。在类中实现异步操作,并提供反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后返回执行结果给UI Thread。
3. ThreadPoolExecutor
ThreadPoolExecutor提供了一组线程池,可以管理多个线程并执行任务。一方面,它减少了每个并行任务独立创建线程的开销;另一方面,它可以管理多个并发线程的公共资源,从而提高多线程效率。这比较适用于一组任务的执行。
Executors 是一个工具类,它利用工厂模式对 ThreadPoolExecutor 进行封装,并提供四种创建 ExecutorService 的方法。这四种方法分别是:
1. `Executors.newFixedThreadPool()`:创建一个定长的线程池。当提交一个任务时,线程池会创建一个新的线程来执行任务,直到达到线程池的最大长度。此时,线程池会保持长度不变。
2. `Executors.newCachedThreadPool()`:创建一个可缓存的线程池。如果当前线程池的长度超过了处理任务的需要,它可以回收空闲的线程。当需要增加线程时,它可以灵活地添加新的线程,而不会限制线程池的长度。
3. `Executors.newScheduledThreadPool()`:创建一个定长且支持定时和周期性任务执行的线程池。类似于 Timer。
4. `Executors.newSingleThreadExecutor()`:创建一个单线程化的 executor。它只创建一个唯一的 worker 线程来执行任务。
除了上述四种常见的 ExecutorService 创建方式外,还有一个值得关注的类:`IntentService`。
`IntentService` 是 Service 的一个子类,它继承自 Service,用于接收并处理通过 Intent 传递的异步请求。客户端可以通过调用 `startService(Intent)` 启动一个 IntentService。在 IntentService 中,利用一个工作线程依次处理顺序过来的请求。当所有请求处理完成后,工作线程会自动结束服务。