Android主线程卡顿问题:Callable与Future使用疑问
问题根源直击
兄弟,你这UI卡顿的问题其实就是踩了Future.get()的坑!你在主线程里直接调用了这个阻塞方法,它会把主线程死死按住,直到后台任务跑完才松手——更糟的是你用的是SingleThreadExecutor,10个任务得串行执行,主线程被卡10个任务的总时长,Fragment事务自然要等所有任务完事儿才能执行,不卡才怪!
看你这段代码里的关键问题点:
consumer.accept(serviceExecutor.submit(() -> ...).get().body().string());
这里的.get()就是罪魁祸首,它直接把主线程挂起,完全阻塞了UI线程的工作。
解决方案
1. 扔掉阻塞的get(),改用异步回调
别在主线程等结果,让后台任务跑完后主动通知主线程更新。你可以把Consumer的调用放到任务内部,完成后通过主线程的Handler切回UI线程执行:
@Override public void getCIFilesType(Consumer<String> consumer) { serviceExecutor.submit(() -> { try { // 后台执行网络请求 String result = service.getCi(EsupFactory.getConfigString(SETTING_ROOT_CI) + "GetCI", translator.makeCiJsonObject("PCiName", "CI_FilesType")) .execute() .body() .string(); // 切回主线程处理结果 new Handler(Looper.getMainLooper()).post(() -> consumer.accept(result)); } catch (IOException e) { e.printStackTrace(); // 异常情况也别忘了在主线程处理 new Handler(Looper.getMainLooper()).post(() -> consumer.accept(null)); } }); // 这里直接返回,主线程该干嘛干嘛去 }
2. 优化线程池(可选,提升任务执行效率)
你用的SingleThreadExecutor是串行执行任务,10个任务得挨个来。如果这些接口请求之间没依赖,换成固定线程池或者缓存线程池让任务并行跑,能大幅缩短总耗时:
// 比如根据CPU核心数创建固定线程池,避免过度并发 ExecutorService serviceExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // 短任务也可以用缓存线程池,自动调整线程数 // ExecutorService serviceExecutor = Executors.newCachedThreadPool();
不过注意别搞太多并发请求,免得服务端给你返回429或者直接拒绝。
3. 确保Fragment事务不受阻塞
你说只在主线程执行Fragment事务,这点是对的,但之前因为get()阻塞了主线程,导致事务被延迟。只要去掉阻塞调用,主线程就能立刻处理Fragment切换,不会再卡顿。
额外提醒
- 记得在Fragment销毁时关闭线程池,防止内存泄漏:
@Override public void onDestroy() { super.onDestroy(); serviceExecutor.shutdown(); // 如果需要强制终止未完成任务,用shutdownNow(),但要做好任务中断的处理 // serviceExecutor.shutdownNow(); }
- 别只打印异常堆栈,最好给上层返回错误状态,方便UI层给用户提示错误信息。
内容的提问来源于stack exchange,提问作者Cyrus the Great
相关产品推荐
相关产品推荐

