使用Retrofit2切换API后仍报W/System: A resource failed to call close如何解决
Retrofit2 报错问题定位与解决方法
问题复现
修改baseUrl对接其他API后程序报错,修复配置甚至切回原有正常API后仍抛出相同错误,同时附带警告:
W/System: A resource failed to call close.
定位步骤
- 首先排查缓存残留问题:Android Studio增量编译、APP本地缓存都可能导致旧代码残留,即使改了配置也运行旧逻辑
- 其次排查接口权限问题:favqs的公开API需要携带授权请求头才能正常调用,未携带头信息会返回401未授权错误
- 再排查空指针风险:请求失败时
response.body()为null,直接调用会触发崩溃 - 最后排查资源泄漏问题:请求返回错误时,
response.errorBody()持有的IO流未主动关闭,会触发资源未关闭的警告
解决方法
1. 清理缓存排除旧代码干扰
- 卸载测试设备上的对应APP,清除残留数据
- 执行Android Studio顶部菜单
Build -> Clean Project再执行Rebuild Project - 重启Android Studio和测试设备后重新运行测试
2. 给请求增加授权头信息
favqs接口需要携带平台分配的API密钥作为请求头才能正常调用,通过OkHttp拦截器统一添加头信息:
// 先构建带请求头的OkHttpClient OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(chain -> { Request originalRequest = chain.request(); Request updatedRequest = originalRequest.newBuilder() // 替换为你自己申请的favqs API密钥 .header("Authorization", "Token token=\"你的API密钥\"") .method(originalRequest.method(), originalRequest.body()) .build(); return chain.proceed(updatedRequest); }) .build(); // 把okHttpClient设置给Retrofit Retrofit.Builder builder = new Retrofit.Builder() .baseUrl("https://favqs.com/api/") .client(okHttpClient) // 新增这行 .addConverterFactory(GsonConverterFactory.create());
3. 优化响应处理逻辑,增加资源释放
修改onResponse方法,增加非空判断,请求失败时主动关闭errorBody释放资源:
@Override public void onResponse(Call<Example> call, Response<Example> response) { if (response.isSuccessful() && response.body() != null) { Example repos = response.body(); Log.d("mylog1", String.valueOf(repos)); listView.setAdapter(new MyAdapter(MainActivity.this, repos)); } else { // 主动关闭错误响应的流,避免资源泄漏 if (response.errorBody() != null) { try { response.errorBody().close(); } catch (IOException e) { e.printStackTrace(); } } Toast.makeText(MainActivity.this, "请求失败,错误码:" + response.code(), Toast.LENGTH_SHORT).show(); } }
4. 页面销毁时主动取消请求
把Call<Example> call改为MainActivity的成员变量,在onDestroy生命周期中主动取消未完成的请求,避免内存泄漏和资源泄漏:
public class MainActivity extends AppCompatActivity { private ListView listView; private Call<Example> call; // 定义为成员变量 @Override protected void onCreate(Bundle savedInstanceState) { // ...原有逻辑不变 call = client.reposForUser(); // 不要局部定义,赋值给成员变量 // ...原有请求逻辑不变 } @Override protected void onDestroy() { super.onDestroy(); // 页面销毁时取消未完成的请求 if (call != null && !call.isCanceled()) { call.cancel(); } } }
内容的提问来源于stack exchange,提问作者Semenov Nilolay
相关产品推荐
相关产品推荐

