@RitcheeQinG
2020-03-23T08:29:05.000000Z
字数 11296
阅读 436
Android
Reference
Handler Google Doc
Juejin
以下内容来自API27官方JavaDoc
Handler能够发送和处理消息和与线程消息队列相关的Runnable对象。每个Handler实例都和单个线程及其消息队列关联。创建一个Handler时,它会和创建它的线程/消息队列绑定,因此它回将消息和runnable发给那个消息队列,且当它们从消息队列中出来时,回执行它们。
post
: 给线程排队来使其在接到相应消息时被消息队列处理,此消息队列是Handler创建时绑定的消息队列/线程postAtTime
postDelayed
sendEmptyMessage
sendMessage
———— handleMessage
sendMessageAtTime
sendMessageDelayed
Handler()
默认,不设置callback和async,必须在已经初始化过Looper的线程中创建Handler(Callback callback)
可以自己实现Callback接口来处理消息,必须在已经初始化过Looper的线程中创建,Callback可以为空Handler(Looper looper)
自己创建一个Looper来初始化HandlerHandler(Looper looper, Callback callback)
Handler(boolean async)
让Handler严格异步处理消息,异步消息不需要和同步消息相关的全局排序,也不受同步屏障限制Handler(Callback callback, boolean async)
以上的构造方法除了自己创建Looper之外都会将默认行为传到这里Handler(Looper looper, Callback callback, boolean async)
Callback
handleMessage(Message msg)
dispatchMessage(Message msg)
处理系统消息getMain()
获取一个主线程的handler,已标记为hidemainIfNull()
判断Handler是否为空,为空则返回一个主线程的Handler,已标记为HidegetTraceName()
返回message中的what,已标记为hidegetMessageName()
将what中的内容转为16进制再输出obtainMessage()
获取一个Handler为当前Handler的新Message,效率比创建和分配新的实例要高,如果不需要当前Handler,可以直接Message.obtain()
obtainMessage(int what)
获取并设置whatobtainMessage(int what, Object obj)
obtainMessage(int what, int arg1, int arg2)
obtainMessage(int what, int arg1, int arg2, Object obj)
post
post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
很明显就是发送一个0延迟的message,runnable运行在Handler的绑定线程上。如果成功放入消息队列中,返回true,失败为false,一般情况下是已经存在一个正在处理该消息队列的Looper了
runWithScissors(final Runnable r, long timeout)
文档部分原文:This method is prone to abuse and should probably not be in the API. If we ever do make it part of the API, we might want to rename it to something less funny like runUnsafe().
removeCallbacks(Runnable r)
把runnable在消息队列中的post全部删掉removeCallbacks(Runnable r, Object token)
把带token的post都删掉,如果token为空,则全删掉sendMessage(Message msg)
把消息推进消息队列末尾,会被handleMessage方法接收,成功返回truesendEmptyMessage(int what)
发一个只有what值的messagesendEmptyMessageDelayed(int what, long delayMillis)
sendEmptyMessageAtTime(int what, long uptimeMillis)
sendMessageDelayed(Message msg, long delayMillis)
sendMessageAtTime(Message msg, long uptimeMillis)
sendMessageAtFronOfQueue(Message msg)
众所周知,并不建议使用这个removeMessages(int what)
去掉又有带该what值的messageremoveMessages(int what, Object object)
带what和object的messageremoveCallbacksAndMessages(Object token)
token为空的话删掉所有的hasMessages(int what)
hasMessagesOrCallbacks()
hasMessages(int what, Object object)
hasCallbacks(Runnbale r)
getLooper
拿到绑定此handler的looper
官方:if we can get rid of this method, the handler need not remember its loop, we could instead export a getMessageQueue() Method..
public final void dump(Printer pw, String prefix)
不知道干嘛用的
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()
方法
/**
* Constructs a HandlerThread.
* @param 线程名称
* @param priority 运行Thread的优先级,值必须来自 {@link android.os.Process}
* 而不是Java的Thread类
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
顺便关注一下priority:
/**
* Standard priority of application threads.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_DEFAULT = 0;
/*
* ***************************************
* ** Keep in sync with utils/threads.h **
* ***************************************
*/
/**
* Lowest available thread priority. Only for those who really, really
* don't want to run if anything else is happening.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_LOWEST = 19;
/**
* Standard priority background threads. This gives your thread a slightly
* lower than normal priority, so that it will have less chance of impacting
* the responsiveness of the user interface.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_BACKGROUND = 10;
/**
* Standard priority of threads that are currently running a user interface
* that the user is interacting with. Applications can not normally
* change to this priority; the system will automatically adjust your
* application threads as the user moves through the UI.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_FOREGROUND = -2;
/**
* Standard priority of system display threads, involved in updating
* the user interface. Applications can not
* normally change to this priority.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_DISPLAY = -4;
/**
* Standard priority of the most important display threads, for compositing
* the screen and retrieving input events. Applications can not normally
* change to this priority.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8;
/**
* Standard priority of audio threads. Applications can not normally
* change to this priority.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_AUDIO = -16;
/**
* Standard priority of the most important audio threads.
* Applications can not normally change to this priority.
* Use with {@link #setThreadPriority(int)} and
* {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
* {@link java.lang.Thread} class.
*/
public static final int THREAD_PRIORITY_URGENT_AUDIO = -19;
/**
* Minimum increment to make a priority more favorable.
*/
public static final int THREAD_PRIORITY_MORE_FAVORABLE = -1;
/**
* Minimum increment to make a priority less favorable.
*/
public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1;
基本上,值越大代表优先级越低
onLooperPrepared()
protected void onLooperPrepared() {
}
留给子类重写,用于在Looper开始loop之前做一些初始化工作
run()
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
调用start后这里便会开始执行,在这个线程绑定一个Looper
getLooper()
/**
* 返回线程绑定的Looper,如果线程还没调用start,或者因为其他原因
* isAlive()返回false,这个方法会返回空。如果这个线程已经start了,
* 阻塞到Looper初始化成功为止。
*/
public Looper getLooper() {
...
return mLooper;
}
用于返回这个线程绑定的Looper,用这个Looper创建绑定的Handler,操作也会执行在这个线程上
getThreadHandler()
返回线程绑定的Handler,已被隐藏,不再使用
quit()
立刻退出looper,已退出返回true
quitSafely()
等到剩下的消息都处理完了再退出looper,已退出返回true
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
HandlerThread handlerThread;
Handler handler;
private void initHandler() {
handlerThread = new HandlerThread("MyThread");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
handler.post(new Runnable() {
@Override
public void run() {
...
}
});
}
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
public abstract class AsyncTask<Params, Progress, Result> {
...
private static InternalHandler sHandler;
private final Handler mHandler;
...
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
this((Looper) null);
}
/**
* @hide
*/
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
...
}
}
从这里就能看出来,它是只能继承使用的,而三个定义在这里的泛型名称分别是用于三个步骤方法的。
而两个Handler,mHandler和sHandler其实都是同一个,因为第二个构造方法被标注为hide了,要使用Looper就只能为空,所以注释里一直在强调一定运行在UI线程中,不在UI线程的话,先不说Handler创建时可能抛Exception,最后处理消息时也发不回UI线程来。
关于InternalHandler
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
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
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
消息类型两种,Result和Progress,可以看出来onProgressUpdate, onPostExecute和onCancelled都是从这里收到消息,在主线程处理的。
发消息的地方:
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
其中,publishProgress是主动调用的,postResult则在WorkerRunnable和FutureTask中
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
Result result = null;
try {
result = doInBackground(mParams);
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
里面多余的代码被去掉了,执行时也就是
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("...");
case FINISHED:
throw new IllegalStateException("...");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
在正式执行futureTask之前,onPreExecute会被调用,而刚开始会判断状态,代表这个task不能再运行第二次。
此外,一般使用AsyncTask开始时都是调用.execute()
方法,但AsyncTask还提供了.executeOnExecutor(Executor exec, Params... params)
这个方法,可以通过自定义Executor的方式来同时执行更多的任务。
举例:
new CustomExecutor().executeOnExecutor(new ThreadPoolExecutor(15, 200, 10,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()));