Android Crashlytics显示崩溃但未定位到自有代码,如何排查?
排查ArrayList并发修改崩溃的步骤
从崩溃栈可以看出,ConcurrentModificationException发生在ArrayList的迭代过程中,结合协程Flow的调用链,核心问题是遍历ArrayList的同时,有其他线程/协程对列表进行了修改。由于ProGuard混淆导致栈轨迹未指向自有代码,可按以下步骤排查:
1. 修复Crashlytics的符号映射还原
- 检查Gradle配置,确保Release构建时自动上传混淆映射文件:
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' firebaseCrashlytics { mappingFileUploadEnabled true } } } } - 若之前映射文件上传错误,可在Firebase控制台的对应崩溃报告中,手动上传
app/build/outputs/mapping/release/mapping.txt文件,还原混淆后的代码栈轨迹。
2. 定位并发访问ArrayList的场景
- 排查所有使用
ArrayList并结合Flow的代码(比如调用asFlow()将列表转为Flow的逻辑),重点检查多协程/多线程共享同一个ArrayList的情况:- 比如一个协程在Flow的
collect中遍历列表,另一个协程在后台线程修改该列表; - 或在主线程触发列表修改的同时,后台协程正在遍历。
- 比如一个协程在Flow的
3. 临时规避:替换为线程安全容器
- 若暂时无法定位具体位置,可将涉及并发访问的
ArrayList替换为CopyOnWriteArrayList,它通过写时复制机制避免并发修改异常,适合读多写少的场景。 - 或者用
synchronized块包裹列表的读写操作,保证互斥:// 修改列表时同步 synchronized(targetList) { targetList.add(newItem) } // 遍历列表时同步 synchronized(targetList) { targetList.forEach { /* 处理逻辑 */ } }
4. 本地复现崩溃
- 模拟并发场景:用
Dispatchers.IO和Dispatchers.Main同时操作同一个ArrayList,配合Flow的收集逻辑,尝试复现崩溃。 - 开启StrictMode,检测主线程的不合理操作,可能发现潜在的并发访问问题。
5. 补充ProGuard规则,保留栈信息
- 在
proguard-rules.pro中添加以下规则,保留自有代码的文件名和行号:
这样即使混淆,Crashlytics也能显示原始代码的位置信息。-keepattributes SourceFile,LineNumberTable -renamesourcefileattribute SourceFile
内容的提问来源于stack exchange,提问作者TheDragoner
相关产品推荐
相关产品推荐

