Android应用出现Choreographer丢帧警告、API请求响应慢该如何优化?
问题核心原因
你遇到的跳帧警告核心原因是耗时操作直接在主线程执行,具体问题点如下:
- 网络请求、HTTP可达性检测都是耗时操作,你在
getClassTeacherList()方法中直接在主线程调用isServerReachable()、serverAuthenticateService.getClassTeacherList()两个网络相关方法,直接阻塞主线程10s以上,才会出现跳几百帧的警告 - 每次业务请求前额外多执行了一次服务器可达性HTTP请求,等于一次业务操作要跑两次网络,额外拉长了整体耗时
- 仅在401刷新token逻辑里开了子线程,正常请求全部走主线程,没有统一的异步请求调度逻辑
具体优化方案
1. 所有网络操作移到子线程执行
Android要求所有网络、IO、复杂计算操作都不能在主线程执行,你可以直接修正请求逻辑,示例代码如下:
private void getClassTeacherList() { academicPeriod = (AcademicPeriod) mSpnPeriod.getItemAtPosition(keyPos); // 所有网络操作全部丢到子线程执行 new Thread(() -> { // 仅做轻量的本地网络连通判断,不要做HTTP请求 if (!isNetWorkAvailable(getApplicationContext())) { // 操作UI必须切回主线程 runOnUiThread(() -> getMsgBox("No connection", "No connection")); return; } // 直接执行业务请求,不要额外做服务器可达检测 classTeacherList = serverAuthenticateService.getClassTeacherList(selClass.getId(),academicPeriod.getId(), authtoken, getApplicationContext()); if (AppBackupCache.checkToken == 200) { showClassTeacherList(); } else if (AppBackupCache.checkToken == 401) { manager.invalidateAuthToken("com.lss.loop", authtoken); authtoken = null; final AccountManagerFuture<Bundle> future = manager.getAuthToken(mAccount, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, new Bundle(), true, null, null); try { Bundle bnd = (Bundle) future.getResult(); authtoken = bnd.getString("authtoken"); if (authtoken != null) { classTeacherList = serverAuthenticateService.getClassTeacherList(selClass.getId(),academicPeriod.getId(), authtoken, getApplicationContext()); if (AppBackupCache.checkToken == 200) { showClassTeacherList(); return; } else { runOnUiThread(() -> getMsgBox("Error", "Something went wrong")); return; } } runOnUiThread(() -> getMsgBox("", "Token not refreshed....")); } catch (Exception e) { e.printStackTrace(); } } AppBackupCache.checkToken = 401; }).start(); } // 仅做轻量的本地网络状态判断,不要发起HTTP请求 public boolean isNetWorkAvailable(Context applicationContext) { ConnectivityManager connMan = (ConnectivityManager) applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = connMan.getActiveNetworkInfo(); return netInfo != null && netInfo.isConnected(); }
2. 移除冗余的服务器可达性检测
你当前的逻辑等于每次业务请求都要先发起一次HTTP请求验证服务器是否可达,耗时直接翻倍,完全没有必要:
- 只需要用
ConnectivityManager判断本地网络是否连通即可 - 业务请求本身如果超时、失败,直接弹出对应错误提示即可,不需要提前做可达性校验
3. 优化网络请求框架
你当前使用的RestTemplate同步请求适配性很差,推荐换成移动端专用的网络方案:
- 换成
OkHttp+Retrofit的组合,原生支持异步请求,自动调度线程,不需要手动维护子线程 - 开启网络缓存,相同参数的请求可以直接读取本地缓存,不需要每次都发起服务器请求,大幅提升响应速度
- 统一封装token过期刷新逻辑,不需要每个接口单独写401处理代码,减少重复逻辑
4. 其他细节优化
- 单选按钮切换时,先取消上一个未完成的请求,避免多个请求并行占用资源
- 列表Adapter不要每次请求成功都重新创建,只更新数据集后调用
notifyDataSetChanged()即可,减少UI创建耗时 - 优化RecyclerView布局,开启Item缓存,减少列表渲染的耗时
内容的提问来源于stack exchange,提问作者KJEjava48
相关产品推荐
相关产品推荐

