如何同步发起Retrofit请求且避免Main Thread Exception?
问题分析
你之前的两种尝试都有核心问题:
- 第一次直接在UI线程调用
call.execute():Android禁止主线程执行网络操作,必然触发NetworkOnMainThreadException。 - 第二次用
IntentService:后台请求能成功,但IntentService的执行流程和按钮点击的UI回调完全异步脱节,你的if (mGoToNewLandingPage)判断会在请求完成前就执行,永远拿不到正确结果。
可行解决方案
核心思路:网络请求放在后台线程执行,请求完成后切回主线程处理Fragment跳转,同时避免阻塞UI线程导致ANR。
方案一:Kotlin 协程(推荐,Android官方主推)
利用lifecycleScope绑定Activity生命周期,自动处理内存泄漏,代码简洁:
button.setOnClickListener { lifecycleScope.launch { // 显示加载弹窗,防止用户重复点击 val loadingDialog = ProgressDialog.show(this@YourActivity, "", "加载中...", true) try { // 切换到IO线程执行同步网络请求 val response = withContext(Dispatchers.IO) { RestServices.getInteractionServices().getLandingPage().execute() } if (response.isSuccessful) { val landingResponse = response.body() val goToNewPage = landingResponse?.shouldGoToNewPage ?: false // 切回主线程执行Fragment跳转 val targetFragment = if (goToNewPage) { LandingSaleV3Fragment.newInstance() } else { NewLandingSaleFragment.newInstance() } supportFragmentManager.beginTransaction() .replace(R.id.container, targetFragment) .commit() } else { Toast.makeText(this@YourActivity, "请求失败", Toast.LENGTH_SHORT).show() } } catch (e: IOException) { e.printStackTrace() Toast.makeText(this@YourActivity, "网络异常", Toast.LENGTH_SHORT).show() } finally { loadingDialog.dismiss() } } }
方案二:Java 线程池 + Handler(纯Java项目适用)
用线程池执行后台请求,通过Handler切回主线程处理UI操作:
button.setOnClickListener(v -> { // 显示加载弹窗 ProgressDialog loadingDialog = ProgressDialog.show(YourActivity.this, "", "加载中...", true); // 线程池执行网络请求 Executors.newSingleThreadExecutor().execute(() -> { InteractionServices interactionServices = RestServices.getInteractionServices(); Call<GetLandingResponse> call = interactionServices.getLandingPage(); try { Response<GetLandingResponse> response = call.execute(); if (response.isSuccessful()) { GetLandingResponse landingResponse = response.body(); boolean goToNewPage = landingResponse != null && landingResponse.shouldGoToNewPage(); // 切回主线程处理跳转 new Handler(Looper.getMainLooper()).post(() -> { Fragment targetFragment = goToNewPage ? LandingSaleV3Fragment.newInstance() : NewLandingSaleFragment.newInstance(); getSupportFragmentManager().beginTransaction() .replace(R.id.container, targetFragment) .commit(); loadingDialog.dismiss(); }); } else { new Handler(Looper.getMainLooper()).post(() -> { Toast.makeText(YourActivity.this, "请求失败", Toast.LENGTH_SHORT).show(); loadingDialog.dismiss(); }); } } catch (IOException e) { e.printStackTrace(); new Handler(Looper.getMainLooper()).post(() -> { Toast.makeText(YourActivity.this, "网络异常", Toast.LENGTH_SHORT).show(); loadingDialog.dismiss(); }); } }); });
注意事项
- 必须处理请求失败场景(网络异常、接口错误码),避免用户无反馈
- 不要用
CountDownLatch等方式在UI线程等待后台请求,会触发ANR(应用无响应) - 绑定Activity生命周期的组件(如
lifecycleScope)能避免内存泄漏,不要用全局线程池或无绑定的Handler
内容的提问来源于stack exchange,提问作者nikolas1903
相关产品推荐
相关产品推荐

