You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何同步发起Retrofit请求且避免Main Thread Exception?

问题分析

你之前的两种尝试都有核心问题:

  1. 第一次直接在UI线程调用call.execute():Android禁止主线程执行网络操作,必然触发NetworkOnMainThreadException。
  2. 第二次用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 12:45:43