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

Retrofit断网时请求崩溃且无Logcat堆栈追踪的问题求助

Retrofit断网时请求崩溃且无Logcat堆栈追踪的问题求助

我是Android开发新手,最近在玩Retrofit+Jetpack Compose,在线状态下请求一切正常,但断网时请求会直接崩溃,而且我写的异常捕获没起作用,Logcat也没给出完整堆栈,只显示“fatal exception”。我已经在Manifest里加了INTERNET和ACCESS_NETWORK_STATE权限,实在搞不懂哪里出问题了,麻烦大家帮我看看!

我的代码如下:

@Composable 
fun api_call_screen(navController: NavController){ 
    var todos by rememberSaveable { mutableStateOf<List<todos>>(emptyList()) } 
    var loading by rememberSaveable { mutableStateOf<Boolean>(true) } 
    var error by rememberSaveable { mutableStateOf<String?>(null) } 

    LaunchedEffect(Unit) { 
        val todosresponse = RetrofitInstance.api.gettodo() 
        val data = try { 
            if(todosresponse.isSuccessful() && todosresponse.body() != null){ 
                todos = todosresponse.body() ?: emptyList() 
                Log.e("Api_CALL","Empty List") 
            }else{ 
                todos=emptyList() 
                error="Something went wrong" 
            } 
        } catch (e : Exception){ 
            error="Something went wrong" 
            todos=emptyList() 
        } finally { 
            loading=false 
        } 
    } 

    Box(modifier = Modifier.fillMaxSize()){ 
        if(loading){ 
            CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) 
        }else if(error !=null){ 
            Text("$error", modifier = Modifier.align(Alignment.Center)) 
        } else if (todos==emptyList<todos>()){ 
            Text("No Data", modifier = Modifier.align(Alignment.Center)) 
        } else{ 
            LazyColumn { 
                items(items = todos){ todo ->
                    Text(todo.title, modifier = Modifier.padding(16.dp)) 
                } 
            } 
        } 
    } 
}

兄弟,我一眼就看到问题所在了!你的try-catch范围完全错了!

你现在是先执行了RetrofitInstance.api.gettodo(),把结果赋值给todosresponse,之后才进入try块判断response的状态。但Retrofit的同步请求在断网这种场景下,调用gettodo()的时候就会直接抛出IOException,而这个调用根本不在你的try-catch包裹范围内,所以异常会直接逃逸导致崩溃,自然也不会被你的catch块捕获。

修复方案:把Retrofit的接口调用放到try块里面

把获取response的代码移到try块内部,这样网络异常才能被正常捕获,另外还要注意你代码里的一个小错误:isSuccessful()是错的,Retrofit的Response.isSuccessful是一个属性,不是方法,要去掉括号:

LaunchedEffect(Unit) {
    var todosresponse: Response<List<todos>>? = null
    val data = try {
        // 把接口调用移到try块里,这样网络异常会被捕获
        todosresponse = RetrofitInstance.api.gettodo()
        if(todosresponse.isSuccessful && todosresponse.body() != null){
            todos = todosresponse.body() ?: emptyList()
            Log.e("Api_CALL","Empty List")
        }else{
            todos=emptyList()
            error="请求失败,请稍后重试"
        }
    } catch (e: IOException) {
        // 专门捕获网络相关异常,给用户更明确的提示
        error = "网络连接失败,请检查网络"
        todos=emptyList()
        // 打印异常信息,方便自己调试
        e.printStackTrace()
    } catch (e : Exception) {
        // 兜底处理其他异常
        error="请求出错,请稍后重试"
        todos=emptyList()
    } finally {
        loading=false
    }
}

额外建议:

  • Logcat堆栈排查:你说Logcat没堆栈,可能是没开对过滤条件。可以在Logcat顶部选择“Error”级别,或者直接搜索“AndroidRuntime”,App崩溃的完整堆栈一般都会在这里输出。
  • 用Retrofit协程风格接口:推荐给你的Retrofit接口加上suspend修饰符,适配协程的异常处理逻辑会更顺畅:
    interface TodoApi {
        @GET("todos")
        suspend fun gettodo(): Response<List<todos>>
    }
    
  • 提前判断网络状态:虽然Retrofit会抛网络异常,但你也可以用ConnectivityManager提前判断网络状态,给用户更及时的反馈,避免不必要的请求。

我之前也踩过这个try-catch范围的坑,把接口调用放到try块里就解决了,你试试看!


内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:13:09