除了Thread,Android中扮演线程的角色还有:AsyncTask、HandlerThread、IntentService。
AsyncTask:内部封装线程池、handler,便于在子线程中更新UI。
HandlerThread:可以使用消息循环的线程,在它内部可以使用Handler。
IntentService:内部使用HandlerThread执行任务,完毕后会自动退出。(相比后台线程)因是组件,优先级高,不易被杀死。
线程是操作系统调度的最小单元,是一种受限的资源,不可能无限制的产生。且线程的创建和销毁需要相应的开销。且存在大量线程时,系统会通过时间片轮转的方式调度线程,因此线程不可能做到并行,除非线程数小于等于cpu数。所以需要 线程池,它可以缓存一定数量的线程,避免频繁地线程创建和销毁带来的系统开销。
AsyncTask
Android提供的一个异步类,它封装了handler和线程池,从而简化了更新UI的问题.
基本使用
AsyncTask是一个抽象的泛型类提供三个泛型参数分别为 Params , Progress, Result.
- Params : 输入的参数类型
- Progress : 执行任务的进度
- Result : 返回结果的类型
public abstract class AsyncTask<Params, Progress, Result>
提供了4个核心方法:
-
onPreExecute :主线程中执行,任务开始前.
-
Result doInBackground(Params... params) : 子线程执行,执行任务时.
当我们调用publishProgress(Progress... values)更新任务进度时,会回调onProgressUpdate方法. 返回计算结果Result给onPostExecute方法.
-
onProgressUpdate(Progress... values) : 主线程中执行,任务的执行进度更新时.
-
onPostExecute(Result result) :主线程中执行,任务执行完毕时.
public class AsyncTaskActivity extends AppCompatActivity implements View.OnClickListener {
//...省略部分代码
class MyAsyncTask extends AsyncTask<String, Integer, Robot> {
@Override
protected void onPreExecute() {
mProgressDialog = new ProgressDialog(AsyncTaskActivity.this);
mProgressDialog.setMessage("正在加载");
mProgressDialog.setMax(10);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.show();
}
@Override
protected Robot doInBackground(String... strings) {
Robot robot = null;
if (strings != null && strings.length > 0) {
for (int i = 0; i < 11; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
if (isCancelled()) {
break;
} else if (i == 10) {{
robot = new Robot("i", strings[0]);
}
}
} else {
throw new IllegalArgumentException("please set the params");
}
return robot;
}
@Override
protected void onProgressUpdate(Integer... values) {
if (values != null && values.length > 0) {
mProgressDialog.setProgress(values[0]);
}
}
@Override
protected void onPostExecute(Robot robot) {
mProgressDialog.dismiss();
tvName.setText(robot == null ? "参数不详" : robot.getName());
}
@Override
protected void onCancelled() {
tvName.setText("任务被取消");
}
}
}
首先在onPreExecute初始化了ProgressDialog控件,接着通过doInBackground模拟执行耗时的机器人构造流程.在构造流程中调用了publishProgress去更新执行任务的进度.最后当任务执行完后在onPostExecute更新了机器人名,这时如果点击了取消任务,那么onCancelled则会调用。
基本原理
我们首先从AsyncTask的构造开始,看具体做了哪些操作.
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
//1.初始化Handler
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//2.初始化WorkerRunnable,实际是一个实现Callable接口的类.
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
//...省略具体实现代码,后面再分析.
return result;
}
};
//3.初始化FutureTask封装了WorkerRunnable.
//在run方法中调用了mWorker的Call方法.
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
//...省略具体实现代码,后面再分析.
}
};
}
这里主要干了三个初始化工作.
-
初始化Handler,绑定主线程的Looper.
-
初始化WorkerRunnable,实际是一个实现Callable接口的类.
-
初始化FutureTask封装了WorkerRunnable.
当我们实例化一个AsyncTask后,就会调用execute方法执行任务.接着看源码.
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING://已经是运行状态,抛异常.
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED://已经是完成状态,抛异常.
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();//执行onPreExecute
mWorker.mParams = params;//将输入参数封装到WorkRunnable
exec.execute(mFuture);//执行任务.
return this;
}
在excute方法中调用了executeOnExecutor方法,对这个流程做个小结.
- 检查状态.
- FutureTask持有一个WorkRunnable,WorkRunnable持有传入的参数.
- 最后利用线程池,去执行futureTask任务,这里可以将FutureTask看成相当于Runnable的作用.
线程池的处理流程.
在executeOnExecutor(sDefaultExecutor, params)方法中用到了sDefaultExecutor线程池.我们接着看线程池的实现.
/**
* 用于任务的排队的线程池
*/
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
//1. 插入到任务队列
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();//调用futureTask的run方法
} finally {//任务执行完毕,继续执行下一个任务.
scheduleNext();
}
}
});
if (mActive == null) {//无任务,执行下一个.
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {//不断从队列中取任务
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
/**
* 执行任务的线程池THREAD_POOL_EXECUTOR
*/
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
这里涉及到两个线程池,也是AsyncTask的核心之处.
-
SerialExecutor : 用于任务的排队.
-
- 插入到任务队列.
-
- 无任务或者任务执行完后,不断从队列中取新任务到另一线程池中执行.
-
threadPoolExecutor : 用于真正执行任务.
-
- CORE_POOL_SIZE :核心线程数与CPU核有关
-
- MAXIMUM_POOL_SIZE : 最大线程数与CPU核有关
-
- KEEP_ALIVE_SECONDS, TimeUnit.SECONDS :超时机制为30秒
-
-
- 超时机制也作用于核心线程.
-
-
sPoolWorkQueue : 阻塞队列
正因为SerialExecutor的存在,从上面可以看出3.0之后是串行执行,所以不会有并发问题(执行饱和策略).
通过Call方法最后我们来看执行任务后是如何回调给主线程的.
在futureTask的run方法会回调WorkerRunnable的call方法.
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//回调callable的Call方法,获取异步任务返回值.
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
//...省略部分代码
}
}
这里继续回到最开始初始化WorkerRunnable时代码.
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
/**
* 1.回调doInBackground方法
*/
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
/**
* 2.通过handler将result传递出去
*/
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
/**
* 3. 处理消息
*/
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
//调用finish
result.mTask.finish(result.mData[0]);
break;
//...省略部分代码
}
}
}
private void finish(Result result) {
if (isCancelled()) {
//回调已取消
onCancelled(result);
} else {
//回调onPostExecute
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
Call方法流程小结.
- 回调doInBackground方法.
- 发送消息,通过handler将result传递出去.
- 处理消息,回调onCancelled或onPostExecute.
到这里AsyncTask的实现原理基本分析完成了,至于之前提到的3.0之前是并行的,3.0之后是串行的,如果想要实现并行可以采用如下方式.
//方式一
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params);
//方式二
executeOnExecutor(自定义的线程池,params);
HandlerThread
是一个消息循环的线程,这样就可以在该线程中使用Handler了.
基本使用
private WorkHandler mHandler;
private HandlerThread mHandlerThread;
/*Handler存在一个构造函数,传入一个Looper对象,Handler的handleMessage获取的是Looper的MessageQueue中的Message
因此,handleMessage的调用与Looper对象同属于一个线程,这里我们在构造时传入HandlerThread的Looper对象,
handleMessage运行于HandlerThread线程(也就是一个子线程),所以Handler虽然是在住线程创建,但是它的
handleMessage接收到消息是在HandlerThread线程,执行下代码可以看到打印出如下log:
D/HandlerThreadDemo: HandlerThread/Demo thread receiver the message from thread: main
log也说明,message由主线程传递到了HandlerThread中。
*/
private class WorkHandler extends Handler {
WorkHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String str = (String) msg.obj;
Log.d(TAG, Thread.currentThread().getName() + " thread receiver the message from thread: " + msg.obj);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handlerthread_demo);
mHandlerThread = new HandlerThread("HandlerThread/Demo");
mHandlerThread.start();
mHandler = new WorkHandler(mHandlerThread.getLooper());
Message msg = mHandler.obtainMessage();
msg.obj = Thread.currentThread().getName();
mHandler.sendMessage(msg);
}
对应源码
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
//很简单,构造函数里只是设置了该Thread的名称和优先级。
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
- 首先呢是调用了Looper.prepaer(),该方法为我们的线程创建了一个唯一的Looper和MessageQueue对象
- 接下来有一个同步锁的代码块,里面获取到了创建好的Looper对象将其赋值给当前的mLooper,然后唤醒了锁。注意这里有一个唤醒线程的操作,既然有唤醒锁的操作,那么必定有有个地方使线程处于了阻塞的状态,我们看下出现阻塞的地方。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
通过查找发现到一个getLooper()的方法,该方法返回了当前线程的mLooper对象,还记得Looper是在哪里进行赋值的吗?在线程的run方法里,所以当线程启动之后才能创建Looper并赋值给mLooper,这里的阻塞就是为了等待Looper的创建成功。同时该方法是用Public修饰的,说明该方法是提供外部调用的,Looper创建成功提供给外部使用。
- 接着我们回到run方法,Looper和MessageQueue已经创建成功了,接下来就是启动Looper循环了(即Looper.loop()),别忘了只有Looper循环启动后我们才能时刻观察着MessageQueue,只要有Message了才能立马将Message取出来进行分发处理。
- 在Looper.loop()之前还调用了一个onLooperPrepared()方法,这个方法是干嘛的呢? 看代码可知,只是一个空方法,在使用HandlerThread时重写该方法,方便在Looper轮询消息之前做一些初始化的操作。
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
最后在对象销毁前,调用下面的方法退出Looper循环
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
quit方法实际是调用MessagQueue的removeAllMessagesLocked,移除所有延迟和非延迟的消息,
quitSafely方法调用的是removeAllFutureMessagesLocked方法,该方法只清除延迟的消息,非延迟的消息 还是会进行分发处理。
-
HandlerThread继承于Thread,本质上也是一个线程。
-
HandlerThread的run方法为本线程创建提供了Looper和MessageQueue对象,并开启了Looper轮询消息。
-
通过在需要发送Message的线程中创建Handler,为Handler提供来自HandlerThread的Looper对象。Handler则能 将消息发送到HandlerThread上去进行处理。 注意:这里Handler不仅仅能在主线程创建,在子线程同样能够创建,只需要将对应的Looper提供给Handler即可,所以HandlerThread 不仅适用于和主线程通信,同样适用于和其他子线程通信。
-
最后需要注意的是在我们不需要这个looper线程的时候需要手动停止掉,即调用quit()或者quitSafely()。
-
最后补充一个在实际开发过程中使用到HandlerThread的场景:
存在多个耗时的任务需要放到开启子线程依次去处理(串行处理任务),首先,HandlerThread是一个子线程, 适合处理耗时的任务,其次,Handler分发消息是通过MessageQueue顶部的Message不断的通过Message的next依次取出 Message,符合任务的按顺序串行处理的要求,所以使用HandlerThread就能完美的解决此需求。
IntentService
是一个Service,封装了handlerThread与Handler.
正因为它是一个Service,所以不会容易被系统杀死.具有以下特点.
特点:
- 相对于服务,能够在服务中执行耗时任务.
- 相对于线程,优先级比单纯的线程高.
- 执行完后会自动停止.
基本使用
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public MyIntentService() {
super(TAG);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
String taskName = intent.getStringExtra("taskName");
Log.d(TAG, "taskName: " + taskName);
SystemClock.sleep(2500);
if ("org.jason.taskOne".equals(taskName)){
Log.d(TAG, "do task: "+taskName);
}
}
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy: ");
super.onDestroy();
}
}
private void doIntentService() {
//连续开三个服务测试
Intent intent = new Intent(this, MyIntentService.class);
intent.putExtra("taskName", "org.jason.taskOne");
startService(intent);
intent.putExtra("taskName", "org.jason.taskTw0");
startService(intent);
intent.putExtra("taskName", "org.jason.taskThree");
startService(intent);
}
//调用输出
12-27 14:34:01.338 D/MyIntentService: taskName: org.jason.taskOne
12-27 14:34:03.839 D/MyIntentService: do task: org.jason.taskOne
12-27 14:34:03.840 D/MyIntentService: taskName: org.jason.taskTw0
12-27 14:34:06.341 D/MyIntentService: taskName: org.jason.taskThree
12-27 14:34:08.841 D/MyIntentService: onDestroy:
从上面日志除了可以看出它的特点外,还能发现任务都是按顺序依次执行的.这与它内部的hanlder处理消息有关,因为handler的looper就是按顺序处理消息的,接着我们去看是如何实现的.
基本原理
IntentService是一个继承Service的抽象类.既然是Service我们就按照Service的生命周期来分析.
首先看OnCreate方法流程
public abstract class IntentService extends Service {
@Override
public void onCreate() {
super.onCreate();
//1.初始化一个HandlerThread
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//2.初始化一个Handler,绑定HandlerThread的Looper.这样就能使用handler,给HandlerThread线程发消息了.
//(也就是说绑定了在哪个线程的looper,那么发送的消息就在哪个线程处理)
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
}
接着OnStart方法流程
onStartCommand里面调用了onStart方法,这里直接看此方法.
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
//1.利用handler发送消息,消息内容就是我们传入的intent以及服务id标识.
mServiceHandler.sendMessage(msg);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
//2.处理消息,
//注意:此handler绑定了HandlerThread的looper,所以是在子线程处理消息.
@Override
public void handleMessage(Message msg) {
//a.回调onHandleIntent
onHandleIntent((Intent)msg.obj);
//b.停止服务
stopSelf(msg.arg1);
}
}
最后看onDestroy方法
@Override
public void onDestroy() {
//最后退出looper,这样消息队列才能退出,最终线程才会销毁.不然一直处于阻塞等待状态.
mServiceLooper.quit();
}
前面讲解HandlerThread时也有提过,当不使用时,需调用quit或者quitSafely来终止线程的执行.可以看出系统源码也是有这一步,所以当我们自定义一个具有消息循环的线程一定记得退出,这是良好的编程习惯.