[关闭]
@RitcheeQinG 2020-03-23T08:29:05.000000Z 字数 11296 阅读 436

关于Android Handler

Android


Reference
Handler Google Doc
Juejin

Handler介绍:

以下内容来自API27官方JavaDoc

什么是Handler:

Handler能够发送和处理消息和与线程消息队列相关的Runnable对象。每个Handler实例都和单个线程及其消息队列关联。创建一个Handler时,它会和创建它的线程/消息队列绑定,因此它回将消息和runnable发给那个消息队列,且当它们从消息队列中出来时,回执行它们。

Handler的主要用途

  1. 给消息和runnable定时以便在未来的某个时刻执行
  2. 给一项行为排队来让它在不同的线程中运行

和定时有关的方法

  1. post: 给线程排队来使其在接到相应消息时被消息队列处理,此消息队列是Handler创建时绑定的消息队列/线程
  2. postAtTime
  3. postDelayed
  4. sendEmptyMessage
  5. sendMessage ———— handleMessage
  6. sendMessageAtTime
  7. sendMessageDelayed
  8. Handler可以用sendMessage和post方法来进行子线程和UI线程间的通信

Handler的内部方法等:

构造方法:

  1. Handler() 默认,不设置callback和async,必须在已经初始化过Looper的线程中创建
  2. Handler(Callback callback) 可以自己实现Callback接口来处理消息,必须在已经初始化过Looper的线程中创建,Callback可以为空
  3. Handler(Looper looper) 自己创建一个Looper来初始化Handler
  4. Handler(Looper looper, Callback callback)
    以下三个构造方法被标注为@hide,可以认为async相关的方法在这个版本默认不提供使用
  5. Handler(boolean async) 让Handler严格异步处理消息,异步消息不需要和同步消息相关的全局排序,也不受同步屏障限制
  6. Handler(Callback callback, boolean async) 以上的构造方法除了自己创建Looper之外都会将默认行为传到这里
  7. Handler(Looper looper, Callback callback, boolean async)

其他方法:

  1. post(Runnable r) {
  2. return sendMessageDelayed(getPostMessage(r), 0);
  3. }

很明显就是发送一个0延迟的message,runnable运行在Handler的绑定线程上。如果成功放入消息队列中,返回true,失败为false,一般情况下是已经存在一个正在处理该消息队列的Looper了

HandlerThread

官方Doc

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
开启一个有Looper的线程,需要调用start()方法

构造方法

  1. /**
  2. * Constructs a HandlerThread.
  3. * @param 线程名称
  4. * @param priority 运行Thread的优先级,值必须来自 {@link android.os.Process}
  5. * 而不是Java的Thread类
  6. */
  7. public HandlerThread(String name, int priority) {
  8. super(name);
  9. mPriority = priority;
  10. }
  11. public HandlerThread(String name, int priority) {
  12. super(name);
  13. mPriority = priority;
  14. }

顺便关注一下priority:

  1. /**
  2. * Standard priority of application threads.
  3. * Use with {@link #setThreadPriority(int)} and
  4. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  5. * {@link java.lang.Thread} class.
  6. */
  7. public static final int THREAD_PRIORITY_DEFAULT = 0;
  8. /*
  9. * ***************************************
  10. * ** Keep in sync with utils/threads.h **
  11. * ***************************************
  12. */
  13. /**
  14. * Lowest available thread priority. Only for those who really, really
  15. * don't want to run if anything else is happening.
  16. * Use with {@link #setThreadPriority(int)} and
  17. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  18. * {@link java.lang.Thread} class.
  19. */
  20. public static final int THREAD_PRIORITY_LOWEST = 19;
  21. /**
  22. * Standard priority background threads. This gives your thread a slightly
  23. * lower than normal priority, so that it will have less chance of impacting
  24. * the responsiveness of the user interface.
  25. * Use with {@link #setThreadPriority(int)} and
  26. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  27. * {@link java.lang.Thread} class.
  28. */
  29. public static final int THREAD_PRIORITY_BACKGROUND = 10;
  30. /**
  31. * Standard priority of threads that are currently running a user interface
  32. * that the user is interacting with. Applications can not normally
  33. * change to this priority; the system will automatically adjust your
  34. * application threads as the user moves through the UI.
  35. * Use with {@link #setThreadPriority(int)} and
  36. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  37. * {@link java.lang.Thread} class.
  38. */
  39. public static final int THREAD_PRIORITY_FOREGROUND = -2;
  40. /**
  41. * Standard priority of system display threads, involved in updating
  42. * the user interface. Applications can not
  43. * normally change to this priority.
  44. * Use with {@link #setThreadPriority(int)} and
  45. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  46. * {@link java.lang.Thread} class.
  47. */
  48. public static final int THREAD_PRIORITY_DISPLAY = -4;
  49. /**
  50. * Standard priority of the most important display threads, for compositing
  51. * the screen and retrieving input events. Applications can not normally
  52. * change to this priority.
  53. * Use with {@link #setThreadPriority(int)} and
  54. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  55. * {@link java.lang.Thread} class.
  56. */
  57. public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8;
  58. /**
  59. * Standard priority of audio threads. Applications can not normally
  60. * change to this priority.
  61. * Use with {@link #setThreadPriority(int)} and
  62. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  63. * {@link java.lang.Thread} class.
  64. */
  65. public static final int THREAD_PRIORITY_AUDIO = -16;
  66. /**
  67. * Standard priority of the most important audio threads.
  68. * Applications can not normally change to this priority.
  69. * Use with {@link #setThreadPriority(int)} and
  70. * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
  71. * {@link java.lang.Thread} class.
  72. */
  73. public static final int THREAD_PRIORITY_URGENT_AUDIO = -19;
  74. /**
  75. * Minimum increment to make a priority more favorable.
  76. */
  77. public static final int THREAD_PRIORITY_MORE_FAVORABLE = -1;
  78. /**
  79. * Minimum increment to make a priority less favorable.
  80. */
  81. public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1;

基本上,值越大代表优先级越低

方法:

onLooperPrepared()

  1. protected void onLooperPrepared() {
  2. }

留给子类重写,用于在Looper开始loop之前做一些初始化工作

run()

  1. @Override
  2. public void run() {
  3. mTid = Process.myTid();
  4. Looper.prepare();
  5. synchronized (this) {
  6. mLooper = Looper.myLooper();
  7. notifyAll();
  8. }
  9. Process.setThreadPriority(mPriority);
  10. onLooperPrepared();
  11. Looper.loop();
  12. mTid = -1;
  13. }

调用start后这里便会开始执行,在这个线程绑定一个Looper
getLooper()

  1. /**
  2. * 返回线程绑定的Looper,如果线程还没调用start,或者因为其他原因
  3. * isAlive()返回false,这个方法会返回空。如果这个线程已经start了,
  4. * 阻塞到Looper初始化成功为止。
  5. */
  6. public Looper getLooper() {
  7. ...
  8. return mLooper;
  9. }

用于返回这个线程绑定的Looper,用这个Looper创建绑定的Handler,操作也会执行在这个线程上
getThreadHandler()
返回线程绑定的Handler,已被隐藏,不再使用
quit() 立刻退出looper,已退出返回true
quitSafely() 等到剩下的消息都处理完了再退出looper,已退出返回true

  1. public boolean quitSafely() {
  2. Looper looper = getLooper();
  3. if (looper != null) {
  4. looper.quitSafely();
  5. return true;
  6. }
  7. return false;
  8. }

使用方法

  1. HandlerThread handlerThread;
  2. Handler handler;
  3. private void initHandler() {
  4. handlerThread = new HandlerThread("MyThread");
  5. handlerThread.start();
  6. handler = new Handler(handlerThread.getLooper());
  7. handler.post(new Runnable() {
  8. @Override
  9. public void run() {
  10. ...
  11. }
  12. });
  13. }

AsyncTask

Java Doc API 27:

AsyncTask即Asynchronous Task,异步任务。AsyncTask能更好地利用UI线程,可以运行后台操作然后在UI线程上展示结果,无需创建一堆线程或者Handler。
AsyncTask最好用于短时间操作,不超过数秒钟。如果要长时间保持线程运行一个操作的话,最好使用java.util.concurrent包下面的API,比如Executor,ThreadPoolExecutor,FutureTask。
主要分为三种类型,Params,Progress和Result,即传入的三种泛型。以及四个步骤,onPreExecute,doInBackground,onProgressUpdate和onPostExecute,要注意的是拿来定义泛型的需要是包装类型,比如Integer
AsyncTask是个抽象类,所以必须继承使用(此外如果用做内部类要注意内存泄漏),必须重写doInBackground
使用方法很简单:new MyAsyncTask().execute(.., .., ..)即可
三种泛型:Params,用于传给任务执行的参数
Progress,后台运算过程中打印出来的过程单位
Result,后台运算结果
如果哪种泛型用不上,标注为Void即可,比如
public class MyAsyncTask extends AsyncTask {

}
四个步骤:
onPreExecute(): 在任务被执行之前,在UI线程调用,用于设置任务,比如显示一个Progress Bar
doInBackground(): 在onPreExecute执行完后立刻在后台线程执行,可以把参数传到这里,调用publishProgress可以把参数传到onProgressUpdate以便在UI线程执行
onProgressUpdate(): 同上,可以以任何形式展示当前进度,比如展示进度条或者打log
onPostExecute(): 后台计算完成后在UI线程调用,结果会作为参数(在doInBackground中以return形式)传过来
取消任务
调用cancel(boolean)即可,之后isCancelled()会返回true,onCancelled(Object)会被调用,可以在doInBackground里面不断检查isCancelled()的返回值
线程使用规则:
1. AsyncTask必须在UI线程创建
2. 必须在UI线程加载(API16之后这事会自动完成)
3. execute()方法必须在UI线程执行
4. 不要主动调用里面的四个步骤方法
5. 任务只能执行一次
内存观测:
这点没太看懂,应该是指onPreExecute中和构造中定义的变量,在doInBackground中指向不会受到同步的影响,同理doInBackground中设置和onPostExecute中指向也不会。
执行顺序:
原先默认能同时执行多个任务,现在想要执行多个任务需要传入自定义的Executor

  1. public abstract class AsyncTask<Params, Progress, Result> {
  2. ...
  3. private static InternalHandler sHandler;
  4. private final Handler mHandler;
  5. ...
  6. /**
  7. * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
  8. */
  9. public AsyncTask() {
  10. this((Looper) null);
  11. }
  12. /**
  13. * @hide
  14. */
  15. public AsyncTask(@Nullable Handler handler) {
  16. this(handler != null ? handler.getLooper() : null);
  17. }
  18. /**
  19. * @hide
  20. */
  21. public AsyncTask(@Nullable Looper callbackLooper) {
  22. mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
  23. ? getMainHandler()
  24. : new Handler(callbackLooper);
  25. ...
  26. }
  27. }

从这里就能看出来,它是只能继承使用的,而三个定义在这里的泛型名称分别是用于三个步骤方法的。
而两个Handler,mHandler和sHandler其实都是同一个,因为第二个构造方法被标注为hide了,要使用Looper就只能为空,所以注释里一直在强调一定运行在UI线程中,不在UI线程的话,先不说Handler创建时可能抛Exception,最后处理消息时也发不回UI线程来。

关于InternalHandler

  1. private void finish(Result result) {
  2. if (isCancelled()) {
  3. onCancelled(result);
  4. } else {
  5. onPostExecute(result);
  6. }
  7. mStatus = Status.FINISHED;
  8. }
  9. private static class InternalHandler extends Handler {
  10. public InternalHandler(Looper looper) {
  11. super(looper);
  12. }
  13. @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
  14. @Override
  15. public void handleMessage(Message msg) {
  16. AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
  17. switch (msg.what) {
  18. case MESSAGE_POST_RESULT:
  19. // There is only one result
  20. result.mTask.finish(result.mData[0]);
  21. break;
  22. case MESSAGE_POST_PROGRESS:
  23. result.mTask.onProgressUpdate(result.mData);
  24. break;
  25. }
  26. }
  27. }

消息类型两种,Result和Progress,可以看出来onProgressUpdate, onPostExecute和onCancelled都是从这里收到消息,在主线程处理的。
发消息的地方:

  1. private Result postResult(Result result) {
  2. @SuppressWarnings("unchecked")
  3. Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
  4. new AsyncTaskResult<Result>(this, result));
  5. message.sendToTarget();
  6. return result;
  7. }
  8. @WorkerThread
  9. protected final void publishProgress(Progress... values) {
  10. if (!isCancelled()) {
  11. getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
  12. new AsyncTaskResult<Progress>(this, values)).sendToTarget();
  13. }
  14. }

其中,publishProgress是主动调用的,postResult则在WorkerRunnable和FutureTask中

  1. mWorker = new WorkerRunnable<Params, Result>() {
  2. public Result call() throws Exception {
  3. Result result = null;
  4. try {
  5. result = doInBackground(mParams);
  6. } finally {
  7. postResult(result);
  8. }
  9. return result;
  10. }
  11. };
  12. mFuture = new FutureTask<Result>(mWorker) {
  13. @Override
  14. protected void done() {
  15. try {
  16. postResultIfNotInvoked(get());
  17. } catch (CancellationException e) {
  18. postResultIfNotInvoked(null);
  19. }
  20. }
  21. };

里面多余的代码被去掉了,执行时也就是

  1. @MainThread
  2. public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
  3. Params... params) {
  4. if (mStatus != Status.PENDING) {
  5. switch (mStatus) {
  6. case RUNNING:
  7. throw new IllegalStateException("...");
  8. case FINISHED:
  9. throw new IllegalStateException("...");
  10. }
  11. }
  12. mStatus = Status.RUNNING;
  13. onPreExecute();
  14. mWorker.mParams = params;
  15. exec.execute(mFuture);
  16. return this;
  17. }

在正式执行futureTask之前,onPreExecute会被调用,而刚开始会判断状态,代表这个task不能再运行第二次。
此外,一般使用AsyncTask开始时都是调用.execute()方法,但AsyncTask还提供了.executeOnExecutor(Executor exec, Params... params)这个方法,可以通过自定义Executor的方式来同时执行更多的任务。
举例:

  1. new CustomExecutor().executeOnExecutor(new ThreadPoolExecutor(15, 200, 10,
  2. TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()));
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注