runnable.run()
是当前线程立即同步执行。
view.post(runnable)
是把任务提交到这个View所在线程的消息队列,通常等主线程之后执行。
1. Runnable.run()
- 当前线程立即执行;
- 没执行完之前,后面的代码不会继续
2. view.post(runnable)
- 不会直接调用
run(),而是把Runnable放进与view关联线程的消息队列。 - 绝大多数情况下,
view在主线程创建和使用,所以通常可以理解为把runnable提交给主线程,稍后执行。
3 .举例说明
Log.d("Test", "1");
view.post(() -> {
Log.d("Test", "Runnable");
});
Log.d("Test", "2");
输出是
1
2
Runnable
Log.d("Test", "1");
runnable.run();
Log.d("Test", "2");
输出是
1
Runnable
2
4. 即使在主线程,view.post(runnable)也不会立即执行
比如
button.setOnClickListener(v -> {
Log.d("Test", "before");
v.post(() -> {
Log.d("Test", "posted");
});
Log.d("Test", "after");
});
输出一般是:
before
after
posted
因为当前点击事件也是主线程正在处理的一条消息。
post()提交后新的任务需要等点击回调执行完,主线程回到消息循环后,才有机会处理。
而
button.setOnClickListener(v -> {
Log.d("Test", "before");
runnable.run();
Log.d("Test", "after");
});
输出是:
before
posted
after
5. 为什么常用view.post()获取宽高
通常:
view.post(() -> {
int width = view.getWidth();
int height = view.getHeight();
});
原因不是为了切线程,而是为了延迟到当前布局流程之后执行。 例如在onCreate()中:
int width = view.getWidth()
可能会得到0,因为此时View还没有完成测量和布局。
用view.post(),任务会等到当前主线程任务之后执行。很多时候,到它执行时,View已经完成了一轮测量和布局,因此可以拿到尺寸。
post()本身表达的是“排队执行”,并不严格承诺View一定完成布局。
如果需要明确的监听,需要其他的函数
6. post()的返回值
post()返回boolean,表示任务是否成功加入队列,但是不表示任务是否已经执行完成,只代表提交情况。
7.post()不等于开启新线程
view.post(() -> {
performHeavyTask();
});
这并不会把任务放到后台线程,恰恰相反,通常会放到主线程。
假如performHeavyTask()需要很耗时,需要5s,那么主线程会卡住5s,界面会卡顿甚至出现ANR。