转载源:阿里云-经常使用runOnUiThread(),你真的理解它吗?;
相关参考链接:
CSDN-weifeng的博客-Android线程的使用正确使用姿势
牛客网-Android中Looper的实现原理,为什么调用Looper.prepare()就在当前线程关联了一个Looper对象,它是如何实现的。
CSDN-阿杜的博客-Android多线程消息处理机制(一) Looper、Thread专题
CSDN-elfylin的专栏-Android Thread Looper Handler 关系

摘要:在Android开发的过程中,主线程主要来完成UI绘制和响应用户的操作,默认情况下,我们大部分的代码都是在主线程中执行的,因此我们时刻要考虑主线程的情况。我们都知道要开启一个子线程来完成一个耗时操作,以避免阻塞主线程影响用户体验,甚至ANR。但是子线程执行完要更新UI的时候,我们又必须回到主线程来更新,实现这一功能常用的方法是执行Activity的runOnUiThread()方法:runOnUiThread(newRunnable(){voidrun(){//dosomet

在Android开发的过程中,主线程主要来完成UI绘制和响应用户的操作,默认情况下,我们大部分的代码都是在主线程
中执行的,因此我们时刻要考虑主线程的情况。我们都知道要开启一个子线程来完成一个耗时操作,以避免阻塞主线程影响
用户体验,甚至ANR。但是子线程执行完要更新UI的时候,我们又必须回到主线程来更新,实现这一功能常用的方法是执行
Activity的runOnUiThread()方法:

runOnUiThread(new Runnable() {
void run() {
// do something
}
});

这样就可以很神奇的使run()中的方法在主线程中执行。那么runOnUiThread()是怎么使run()中的代码在主线程中执行的呢?

开始分析

先从Activity的部分源码开始:

final Handler mHandler = new Handler();
private Thread mUiThread;
// …
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
// …
}

代码很简单,首先判断当前的线程是否是主线程,如果是住线程就直接执行Runnable接口的run()方法;但如果不是主线程
呢?这时调用Handler的post(Runnable)方法。那么这个过程又发生了什么了呢?让我们从Looper说起。

Looper

我们创建一个线程并重写它的run()方法,如下:

public class MyThread extends Thread {
@Override
public void run() {
// do something…
}
}

当这个run()方法中的语句执行完的时候,这个线程就结束了,无用了。如果我们为了减小内存而不创建新的线程来复用
这个线程的时候,我们需要它保持存活并等待新的指令。常见的做法是创建一个循环:

public class MyThread extends Thread {
private boolean running;
@Override
public void run() {
while (running) {
// do something…
}
}
}

只要while循环没执行完,线程就保持存活。这就是Looper可以实现的,Looper字面意思就是“循环”,保持线程存活。
关于Looper值得一提的事:

线程默认不会得到Looper;
可以再线程中创建一个Looper;
每个线程只能创建一个Looper。
下面我们用Looper替换white循环:

public class MyThread extends Thread {
@Override
public void run() {
Looper.prepare();
Looper.loop();
}
}

调用Looper.prepare()检查当前线程中是否有Looper,如果没有则创建。调用Looper.loop()后Looper开始循环。
这样,Looper循环并保持线程存活,但这样什么也不做的线程存活是没有意义的。
当创建Looper时,它创建了一个消息队列(MessageQueue),用来存放消息(Message)。

什么是消息

Message实际上就是一些指令的集合。它能保持String,int,Runnables等数据类型。
如果我们想要在特定的线程执行Runnables,我们只需将Runnables放到消息中,并将消息放到这个线程的Looper创建
的消息队列中!那么如何放到消息队列中呢?又用到了Handler。

Handler

Handler就是处理者的意思,他负责将消息放到Looper的消息队列中,当到了执行的时候,他又负责在Looper所绑定的
线程中执行这个消息。
Handler被创建的时候是指向特定的Looper的。有两种不同的创建方式:

在构造方法中指定Looper:
Handler handler = new Handler(Looper looper);
使用空构造方法,此时指向当前线程的Looper:
Handler handler = new Handler();
Handler能非常便利的创建消息并将其添加到Looper的消息队列末尾,如post()。
所以,我们只需将Runnable传到post()中:
handler.post(new Runnable(){
@Override
public void run(){
// do something …
}
});

是不是看上去很眼熟了。

结论

重新回过头来看runOnUiThread()的源码:

final Handler mHandler = new Handler();
private Thread mUiThread;
// …
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
// …
}

首先在主线程里通过无参的构造方法创建一个Handler,这个Handler是指向主线程的。
当执行runOnUiThread()时,当前线程不是主线程,调用mHandler.post(action),将Runnable添加到主线程的消息队列中
这样,Runnable的语句就是在主线程执行的了。

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. Mars Android视频学习笔记——01_14/15_Handler的使用
  3. Android周报第四期
  4. Android(安卓)ANR 详解
  5. Android(安卓)studio 使用 ImageView 加载 gif 文件
  6. Android面试题整理(百度)
  7. Android线程池的详细说明(一)
  8. 深入理解Android中的Handler机制
  9. 快速提高Android开发调试的使用技巧

随机推荐

  1. android SDK 更新出现错误的解决办法
  2. WebView 简单使用一
  3. layout_weight 权重
  4. Android各版本对应的SDK版本
  5. 使用Android studio导入源码工程
  6. 高通平台Android N SystemUI添加qcnvitem
  7. Android强制设置横屏或竖屏
  8. Android 控件抖动效果
  9. Android Studio第二十七期 - RecycleView
  10. Android ViewFlipper简单示例