Android中Runnable内调用API跳转Activity后的线程问题
解决Activity跳转后轮询线程持续运行的问题
老哥,这个问题我之前踩过一模一样的坑——你跳转到Activity2后,原来的轮询Runnable没被正确终止,所以它还在后台持续执行请求。本质原因是线程不受Activity生命周期自动管控,得手动干预停止。下面给你几个实用的解决方案,按需选就行:
方案1:用Handler管理Runnable,跳转前移除回调
如果你的轮询是通过Handler.postDelayed()实现的,那跳转时直接移除这个Runnable的后续回调就能停止轮询。同时别忘了取消正在进行的HTTP请求,避免不必要的资源消耗和内存泄漏。
示例代码(Java):
private Handler mPollHandler = new Handler(Looper.getMainLooper()); private Call mCurrentCall; // 保存当前HTTP请求,方便取消 private Runnable mPollRunnable = new Runnable() { @Override public void run() { // 构建HTTP请求(以OkHttp为例) OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url("https://status.com/key").build(); mCurrentCall = client.newCall(request); mCurrentCall.enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { // 请求失败,未取消则继续轮询 if (!call.isCanceled()) { mPollHandler.postDelayed(mPollRunnable, 1000); } } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful()) { String result = response.body().string(); if ("yes".equals(result)) { // 收到目标响应,停止轮询并跳转 mPollHandler.removeCallbacks(mPollRunnable); runOnUiThread(() -> startActivity(new Intent(Activity1.this, Activity2.class))); } else { // 继续轮询 mPollHandler.postDelayed(mPollRunnable, 1000); } } } }); } }; // 跳转Activity2的方法 private void navigateToActivity2() { // 移除后续轮询回调 mPollHandler.removeCallbacks(mPollRunnable); // 取消正在进行的请求 if (mCurrentCall != null && !mCurrentCall.isCanceled()) { mCurrentCall.cancel(); } startActivity(new Intent(this, Activity2.class)); }
方案2:用volatile标志位控制轮询
定义一个volatile修饰的布尔变量(保证多线程下的可见性),每次轮询前先检查这个标志,一旦标记为停止就终止后续逻辑。
示例代码(Java):
// volatile保证线程间可见性,避免线程读取到旧值 private volatile boolean mShouldStopPolling = false; private Call mCurrentCall; private Runnable mPollRunnable = new Runnable() { @Override public void run() { // 先检查是否需要停止 if (mShouldStopPolling) { return; } // 执行HTTP请求逻辑 OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url("https://status.com/key").build(); mCurrentCall = client.newCall(request); mCurrentCall.enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { if (!mShouldStopPolling && !call.isCanceled()) { new Handler(Looper.getMainLooper()).postDelayed(mPollRunnable, 1000); } } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { if (response.isSuccessful()) { String result = response.body().string(); if ("yes".equals(result)) { mShouldStopPolling = true; runOnUiThread(() -> startActivity(new Intent(Activity1.this, Activity2.class))); } else if (!mShouldStopPolling) { new Handler(Looper.getMainLooper()).postDelayed(mPollRunnable, 1000); } } } }); } }; // 在跳转或Activity销毁时设置停止标志 @Override protected void onDestroy() { super.onDestroy(); mShouldStopPolling = true; if (mCurrentCall != null && !mCurrentCall.isCanceled()) { mCurrentCall.cancel(); } } private void navigateToActivity2() { mShouldStopPolling = true; if (mCurrentCall != null && !mCurrentCall.isCanceled()) { mCurrentCall.cancel(); } startActivity(new Intent(this, Activity2.class)); }
方案3:用Kotlin协程绑定生命周期(推荐Kotlin项目)
如果是Kotlin开发,用lifecycleScope可以让协程自动跟随Activity生命周期,Activity销毁时协程会自动取消,不用手动管理线程,代码更简洁。
示例代码(Kotlin):
// 在Activity中启动协程 lifecycleScope.launch { while (isActive) { // isActive是协程的活跃状态,Activity销毁时会变为false // 假设这是你的Retrofit接口请求 val response = apiService.getStatus() if (response == "yes") { startActivity(Intent(this@Activity1, Activity2::class.java)) break // 跳出循环,终止协程 } delay(1000) // 每秒轮询一次 } }
关键注意点
- 无论用哪种方案,一定要取消正在进行的HTTP请求,否则可能导致内存泄漏(请求回调持有Activity引用),也会浪费网络资源。
- 不要用
Thread.stop()这种过时且不安全的方法来终止线程,这可能导致资源无法释放。 - 如果Activity1只是被压入后台(比如跳转到Activity2后,Activity1还在栈中),可以在
onPause()方法中停止轮询,onResume()中恢复,根据业务需求调整。
内容的提问来源于stack exchange,提问作者tester9
相关产品推荐
相关产品推荐

