安卓使用AsyncTask加载图片时UI卡顿直到加载完成是什么原因?
问题根因
ValueEventListener的onDataChange回调默认运行在主线程,你将图片下载、本地存储、数据库写入这些耗时操作全部放在这个回调里执行,直接阻塞UI线程导致卡顿- 调用
AsyncTask.get()方法会阻塞当前线程等待异步任务返回结果,相当于把异步任务变成了同步执行,进一步拉长了主线程阻塞时间 - 你在遍历每个联系人的时候都重复请求一次Firebase的
Users全量节点,大量重复IO操作,执行效率极低 - 原生
AsyncTask已经被Android官方废弃,默认和主线程共用串行任务队列,大量任务排队会进一步挤压UI操作的执行资源 - 自行实现的图片下载、缓存逻辑没有做任何优化(比如采样率压缩、缓存复用、异步加载回调),性能远低于成熟的图片加载框架
修复方案
1. 调整Firebase数据查询逻辑
不要在每个联系人的遍历中请求全量用户数据,先拉一次全量用户数据存到内存Map(key为手机号,value为用户信息),再遍历本地联系人和Map做匹配,只做一次IO请求。
2. 所有耗时操作移到后台线程执行
把onDataChange里的图片下载、本地存储、数据库写入逻辑全部移到后台线程,比如用Kotlin协程的Dispatchers.IO调度,或者用WorkManager做后台任务调度,不要占用主线程资源。
3. 移除所有AsyncTask.get()阻塞调用
不要用阻塞方式等待异步任务结果,改用回调或者协程的挂起函数获取结果,非必要不要同步执行耗时任务。
4. 替换自行实现的图片加载逻辑
用Glide、Coil等成熟图片加载框架替代自己写的GetImageFromUrl和存储逻辑,这些框架默认会在后台线程异步下载、缓存图片,还支持占位图、采样压缩,加载完成后自动切回主线程更新UI,不需要自己处理线程切换和存储逻辑。如果你确实需要把头像存在本地指定目录,也可以用框架的下载缓存回调实现,不需要自己写IO逻辑。
5. 替换废弃的AsyncTask
如果用Kotlin开发优先用协程处理异步任务,Java开发可以用ExecutorService、HandlerThread或者WorkManager替代AsyncTask,避免串行任务队列阻塞UI相关的异步操作。
6. 优化联系人匹配逻辑
手机号格式化可以用正则替换替代循环遍历,执行效率更高:
val phone_num = phoneNumber.replace(Regex("[^0-9]"), "")
内容的提问来源于stack exchange,提问作者Ayush Mishra
相关产品推荐
相关产品推荐

