Android中主线程与子线程双向通信实现
在Android开发中,线程间通信是常见的需求。虽然大多数场景下我们关注的是子线程完成任务后通知主线程更新UI,但有时也需要从主线程向子线程传递指令,比如触发后台数据同步、配置刷新或任务调度等操作。本文将介绍如何使用Handler和Looper机制实现主线程与子线程之间的双向消息传递。
为了在子线程中接收消息,必须为其创建独立的Looper,这样才能保证Handler能够正常处理消息队列。Android提供了HandlerThread类来简化这一过程,它是一个带有Looper的线程,非常适合用于执行长时间运行的后台任务。
实现步骤
- 在主线程中定义一个Handler用于发送消息到子线程;
- 创建并启动HandlerThread,并获取其Looper; <3>基于该Looper创建子线程的Handler,用于接收和处理来自主线程的消息;
- 通过按钮或其他用户交互触发消息发送。
代码示例
public class CommunicationActivity extends AppCompatActivity implements View.OnClickListener {
private Button startBtn, stopBtn;
private Handler mainHandler;
private Handler backgroundHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_communication);
mainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
Log.d("MainHandler", "Running on thread: " + Thread.currentThread().getName());
Message nextMsg = Message.obtain();
backgroundHandler.sendMessageDelayed(nextMsg, 1000); // 每隔1秒发消息给子线程
}
};
setupBackgroundThread();
findViews();
}
private void setupBackgroundThread() {
HandlerThread workerThread = new HandlerThread("WorkerThread");
workerThread.start();
backgroundHandler = new Handler(workerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Log.d("BackgroundHandler", "Received message on thread: " + Thread.currentThread().getName());
// 模拟处理耗时任务
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 回送消息给主线程
mainHandler.sendEmptyMessage(0);
}
};
}
private void findViews() {
startBtn = findViewById(R.id.btn_start);
stopBtn = findViewById(R.id.btn_stop);
startBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_start) {
mainHandler.sendEmptyMessage(1);
} else if (v.getId() == R.id.btn_stop) {
mainHandler.removeMessages(1);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (backgroundHandler != null) {
backgroundHandler.getLooper().quitSafely();
}
}
}
布局文件(activity_communication.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Sending" />
<Button
android:id="@+id/btn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop Sending" />
</LinearLayout>
上述代码展示了如何建立两个方向的消息通道:主线程通过点击"Start"按钮开始周期性地向子线程发送消息,而子线程在接收到消息后进行简单处理,并反向发送消息回主线程,形成闭环通信。同时,在页面销毁时正确退出子线程的Looper,避免内存泄漏。