Android 常用的异步处理机制有:Handler、Thread、ThreadPool、HandlerThread、IntentService、AsyncTask、RxJava、Coroutines
Handler
Handler 机制主要由四个类实现,分别为 Handler、Looper、MessageQueue、Message,作用如下:
- Message 用于承载线程之间传递的消息
- MessageQueue 是一个用链表实现的先进先出队列,用来存储 Message
- Handler 用于把 Message 插入 MessageQueue,同时实现了 handleMessage 消息处理方法。其中,sendMessage 方法最终会调用到 sendMessageAtTime,从队头开始遍历并根据时间大小进行插入
- Looper 主要是为每个线程开启单独的消息循环,内部 prepare、getLooper、loop 等静态方法操纵的都是 ThreadLocal<Looper> 实例
loop 方法每此循环都会从 MessageQueue 中取出一个消息,然后通过 Message 的 target 属性获取到 Handler 实例,进而调用到 dispatchMessage 函数。在 dispatchMessage 方法中,如果 Message 存在 callback(手动设置,或者通过post(runnable)自动设置),会执行 handleCallback 方法,如果 Handler 的 mCallback 变量不为空,则执行 mCallback.handleMessage 方法,否则执行 Handler 的 handleMessage 方法(实践中我们经常重写这个方法),Looper 处理完成一个消息后则继续循环,若消息队列为空,线程则会阻塞等待
handler.sendEmptyMessage(1);
handler.sendEmptyMessageDelayed(2, 2);
handler.sendEmptyMessage(3);
handler.sendEmptyMessage(6);
handler.sendEmptyMessageDelayed(4, 12);
handler.sendEmptyMessageDelayed(5, 1);
//执行顺序 1 3 6 5 2 4
ThreadLocal
每个线程中保存着 ThreadLocalMap 对象,调用 ThreadLocal 的 get 和 set 方法时,先通过当前 Thread 拿到 ThreadLocalMap 对象,Map 的 key 为 ThreadLocal,value 为要保存的值,现在想为什么 Map 不用 Thread 作为 key 值呢,因为这样就无法在一个线程中保存多个值了,关键点是 get 和 set 会拿到当前线程的 ThreadLocalMap 的概念,以及 TheadLocal 是 key 值
public class ThreadLocal<T> {
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
}
Looper 代码详解
主要有三个方法,Looper#prepare、Looper#getLooper、Looper#loop。Looper#prepare 会创建当前线程对应的 Looper 实例(ThreadLocal#put),Looper#getLooper 会返回当前线程对应的 Looper 实例,Looper#loop 会通过 Looper#getLooper 获取当前线程对应的 Looper,并执行消息队列循环(Message.target.dispatchMessage)
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
final MessageQueue mQueue;
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
}
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
}
Handler 内存泄漏:Runnable 延时消息、消息过多,解决办法有:静态内部类+弱引用、removeCallbacks、removeMessages。具体的泄漏引用链为:
Activity <- Handler <- Message <— MessageQueue <— Looper <— ThreadLocalMap <- Thread
HandlerThread
- 内部在 run 方法中创建线程对应的 Looper,并保存到了 mLooper 变量中
- run 方法和 getLooper 方法做了互斥处理
//HandlerThread 主要是在线程中创建 Looper
public class HandlerThread extends Thread {
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
@Override
public void run() {
Looper.prepare();
Synchronized(this) {
mLooper = Looper.myLooper();
notifyAll();
}
Looper.loop();
}
public Looper getLooper() {
Synchronized(this) {
while(mLooper == null) {
try {
wait();
} catch (Exception e) {
}
}
}
return mLooper;
}
}
IntentService
通过 Service 实现,优先级较高,适用于操作比较固定,顺序执行的任务
IntentService 会在 onStartCommand 方法中把参数(Intent、startId)post 到 Handler 中处理,Handler 通过 HandlerThread 实现,handleMessage 方法中会调用 onHandleIntent 接口,并在消息处理结束后调用 stopSelf(int) 来关闭当前 Service,如果当前 Handler 中还有别的消息要处理,自然无法关闭 Service,因为每次调用 startService 时 Service 都会传入一个 startId 值
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
protected abstract void onHandleIntent(@Nullable Intent intent);
}
AsyncTask
相比于其他异步处理机制,AsyncTask 更擅长 UI 交互。AsyncTask 内部封装了主线程 Handler 和工作线程池(避免不必要线程创建和销毁的开销),创建实例和 execute 方法必须在主线程执行,对应回调方法有 onPreExecute、doInBackground(内部调用 publishProgress)、onProgressUpdate 、onPostExecute
AsyncTask 实例只能执行一次 execute 方法,在 execute 方法中会判断 AsyncTask 实例的状态,如果不是 Pending 状态,则抛出异常,然后调用 onPreExecute 方法,最后 AsyncTask 通过SerialExecutor 来执行任务,SerialExecutor 实现了 executor 接口,SerialExecutor 内部通过队列保存 FutureTask(Runnable任务,在构造方法中初始化,其中,FutureTask封装了WorkerRunnable,WorkerRunnable实现了Callable接口),并顺序传入线程池,因此 AsyncTask模式是串型执行任务的。在 FutureTask 中的 Callable 任务执行结束后,会调用 done 回调方法,AsyncTask 在创建 FutureTask 时实现了 done 方法,在该方法中会给 Handler 发送MESSAGE_POST_RESULT 消息,从而执行 onPostExecute。另外,FutureTask 实现了操纵Runnable 所在线程的 api,包括通过 get 方法获取执行结果,cancel 方法取消执行线程,如果调用 cancel,AsyncTask 则不调用 onPostExecute 回调方法,而是调用 onCancelled 回调方法
public abstract class AsyncTask<Params, Progress, Result> {
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
public AsyncTask() {
this((Looper) null);
}
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null ||
callbackLooper == Looper.getMainLooper() ? getMainHandler() : new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Result result = doInBackground(mParams);
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
postResultIfNotInvoked(get());
}
};
}
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();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
}
public class FutureTask<V> implements RunnableFuture<V> {
public void run() {
if (state != NEW) return;
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
result = c.call();
set(result);
finishCompletion();
}
}
public V get(long timeout, TimeUnit unit) throws TimeoutException {
int s = state;
if (s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}
public boolean cancel(boolean mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null) {
t.interrupt();
}
} finally {
finishCompletion();
}
return true;
}
private void finishCompletion() {
done();
}
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
}
//new UpdateTextTask(MainActivity.this, "1").execute();
//new UpdateTextTask(MainActivity.this, "2").execute();
//new UpdateTextTask2(MainActivity.this, "3").execute();
//验证结果,三个都是顺序执行的
如果执行 AsyncTask 的 execute 方法,默认是采用 DefaultExecutor(同步线程池),各个任务顺序执行,我们也可以调用 executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR),该执行器为 AsyncTask 提供的异步线程池,其中,核心线程数等于cpu数量+1,最小值是2个,最大值是4个,最大线程数量等于cpu数量*2+1,另外我们也可以自己实现Executor
Android 常用的定时任务有:ScheduledExecutorService、Handler.postDelay、AlarmManger、Coroutines、RxJava
注意:AlarmManager 无法精确定时,从 Android 5.1 开始,AlarmManager.setRepeating 将被强制设置为至少 60 秒
class MyService : Service() {
companion object {
const val TIME_INTERVAL = 5000
const val TEST_ACTION = "XXX.XXX.XXX" + "_TEST_ACTION"
}
var pendingIntent: PendingIntent? = null
var alarmManager: AlarmManager? = null
override fun onCreate() {
super.onCreate()
val intentFilter = IntentFilter(TEST_ACTION)
registerReceiver(receiver, intentFilter)
alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager?
val intent = Intent()
intent.action = TEST_ACTION
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> { //6.0低电量模式需要使用该方法触发定时任务
alarmManager!!.setExactAndAllowWhileIdle(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), pendingIntent)
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT -> { //4.4以上 需要使用该方法精确执行时间
alarmManager!!.setExact(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), pendingIntent)
}
else -> { //4。4一下 使用老方法
alarmManager!!.setRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), TIME_INTERVAL.toLong(), pendingIntent)
}
}
}
private var receiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (TEST_ACTION == intent.action) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager!!.setExactAndAllowWhileIdle(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + TIME_INTERVAL, pendingIntent)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager!!.setExact(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + TIME_INTERVAL, pendingIntent)
}
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(receiver)
}
}