之前介绍handler的时候讲过,在 Android 中,UI 操作必须在主线程中进行,不能直接在子线程中更新 UI。今天介绍两种在子线程切换回主线程的方法。
runOnUiThread()
和 Handler.post()
都可以用于切换到 主线程(UI 线程) 执行任务,主要用于 更新 UI。但它们在使用方式、作用范围、底层实现上有所不同。
1. runOnUiThread()
runOnUiThread()
是 Activity
的一个方法,它可以让任务在 主线程(UI 线程) 执行。适用于 在 Activity
内部 从子线程切换到主线程 以更新 UI。
用法:
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("更新 UI");
}
});
Lambda 写法:
runOnUiThread(() -> textView.setText("更新 UI"));
底层原理:
runOnUiThread()
的实现本质上 使用了 Handler.post()
,它会获取 Activity
绑定的 Looper
,然后将任务投递到 主线程消息队列。
适用场景
- 只在
Activity
里使用,不能在Service
、BroadcastReceiver
等组件中用。 - 简单的 UI 更新,比如在
onCreate()
、网络请求回调、异步任务完成后 更新 TextView、Button 等 UI 组件。
完整的代码:实现的效果很简单,2秒后在主界面更新UI,显示 "UI 更新成功!"
public class MainActivity extends AppCompatActivity {
private TextView textView;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main9);
textView = findViewById(R.id.textView);
// 在子线程中执行耗时操作
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000); // 模拟网络请求或其他耗时任务
} catch (InterruptedException e) {
e.printStackTrace();
}
// 切换到主线程更新 UI
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("UI 更新成功!");
}
});
}
}).start();
}
}
2. Handler.post()
Handler.post()
通过 Handler
将任务投递到指定的线程,一般用于 从子线程切换到主线程 处理 UI 更新,也可以用于子线程间通信。
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> textView.setText("更新 UI"));
底层原理
Handler
通过MessageQueue
投递任务,Looper
取出并执行。- 不会判断当前线程,即使
post()
发生在主线程,它也会把任务加入消息队列,可能稍微延迟执行。
适用场景
- 适用于 所有 Android 组件(
Activity
、Service
、Fragment
、BroadcastReceiver
)。 - 可以执行延迟任务(
postDelayed()
)。 - 可在子线程和子线程间通信,不仅限于 UI 更新。
完整代码,实现的效果和上面runOnUiThread()是一样的。2秒延迟后,主界面显示"数据加载完成"
import android.os.Handler;
import android.os.Looper;
public class MainActivity extends AppCompatActivity {
private TextView textView;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main9);
textView = findViewById(R.id.textView);
Handler handler = new Handler(Looper.getMainLooper());
new Thread(() -> {
try {
Thread.sleep(2000); // 模拟网络请求
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(() -> textView.setText("数据加载完成"));
}).start();
}
}