通过查看anr/下的dumptrace日志,搜索空调包名,发现如下日志
"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x731f9d08 self=0xb4000074f82f5380
| sysTid=2790 nice=0 cgrp=foreground sched=0/0 handle=0x767ee3b4f8
| state=R schedstat=( 43403965835908 128373803042 1427593 ) utm=4024919 stm=315476 core=1 HZ=100
| stack=0x7fe0477000-0x7fe0479000 stackSize=8192KB
| held mutexes=
native: #00 pc 00000000000126ec /system/lib64/libz.so (inflate_fast+412)
native: #01 pc 0000000000010d00 /system/lib64/libz.so (inflate+4628)
native: #02 pc 0000000000017b90 /system/lib64/libpng.so (png_process_IDAT_data+132)
native: #03 pc 0000000000017968 /system/lib64/libpng.so (png_push_read_IDAT+480)
native: #04 pc 0000000000016c60 /system/lib64/libpng.so (png_process_data+124)
native: #05 pc 0000000000252fc8 /system/lib64/libhwui.so (SkPngCodec::processData()+344)
native: #06 pc 0000000000254118 /system/lib64/libhwui.so (SkPngNormalDecoder::decodeAllRows(void*, unsigned long, int*)+96)
native: #07 pc 000000000024acd4 /system/lib64/libhwui.so (SkCodec::getPixels(SkImageInfo const&, void*, unsigned long, SkCodec::Options const*)+336)
native: #08 pc 0000000000254e04 /system/lib64/libhwui.so (SkSampledCodec::onGetAndroidPixels(SkImageInfo const&, void*, unsigned long, SkAndroidCodec::AndroidOptions const&)+540)
native: #09 pc 0000000000246174 /system/lib64/libhwui.so (SkAndroidCodec::getAndroidPixels(SkImageInfo const&, void*, unsigned long, SkAndroidCodec::AndroidOptions const*)+744)
native: #10 pc 00000000001b8508 /system/lib64/libhwui.so (doDecode(_JNIEnv*, std::__1::unique_ptr<SkStreamRewindable, std::__1::default_delete<SkStreamRewindable> >, _jobject*, _jobject*, long, long)+2856)
native: #11 pc 00000000001b7828 /system/lib64/libhwui.so (nativeDecodeAsset(_JNIEnv*, _jobject*, long, _jobject*, _jobject*, long, long)+112)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:762)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:575)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:604)
at com.desaysv.svhvac.view.widget.FrameAnimationView.a(SourceFile:174)
at com.desaysv.svhvac.view.widget.FrameAnimationView.d(SourceFile:142)
at com.desaysv.svhvac.view.widget.FrameAnimationView.a(SourceFile:27)
at com.desaysv.svhvac.view.widget.FrameAnimationView$1.handleMessage(SourceFile:109)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7705)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1001)
这是主线程(main 线程)在做【同步 PNG 图片解码】,把 UI 线程堵死了 → 直接造成卡顿、掉帧、操作延迟!
为什么会卡?
图片解码是耗时、耗 CPU操作
绝对不能在主线程做!
但hvac代码的 FrameAnimationView 偏偏就在主线程解码帧动画 → 不卡才怪。
既然指出具体类,那么直接对此处理就好了
if (getVisibility() == VISIBLE) {
// 异步解码 Bitmap,避免阻塞主线程
final int currentIndex = mIndex;
mLoadTask = mExecutor.submit(() -> {
Bitmap newBitmap = decodeBitmap(mDrawables[currentIndex]);
if (newBitmap != null) {
post(() -> {
// 在 UI 线程更新 Bitmap
if (mCurrentBitmap != null && !mCurrentBitmap.isRecycled()) {
mCurrentBitmap.recycle();
}
mCurrentBitmap = newBitmap;
invalidate();
});
}
});
}
非预加载模式下,将 decodeBitmap() 移到后台线程执行(使用已有的 mExecutor 线程池)
解码完成后通过 post() 回到 UI 线程更新 mCurrentBitmap 并调用 invalidate()
复用现有的 mLoadTask 来管理任务,可以在切换资源时取消未完成的加载
预加载模式不受影响,因为它已经是在后台线程加载的
这样修改后,主线程只负责调度和绘制,耗时的 Bitmap 解码在后台线程完成,不会再造成卡顿