Hvac一次卡顿问题分析
通过查看anr/下的dumptrace日志搜索空调包名发现如下日志main prio5 tid1 Native | groupmain sCount1 dsCount0 flags1 obj0x731f9d08 self0xb4000074f82f5380 | sysTid2790 nice0 cgrpforeground sched0/0 handle0x767ee3b4f8 | stateR schedstat( 43403965835908 128373803042 1427593 ) utm4024919 stm315476 core1 HZ100 | stack0x7fe0477000-0x7fe0479000 stackSize8192KB | held mutexes native: #00 pc 00000000000126ec /system/lib64/libz.so (inflate_fast412) native: #01 pc 0000000000010d00 /system/lib64/libz.so (inflate4628) native: #02 pc 0000000000017b90 /system/lib64/libpng.so (png_process_IDAT_data132) native: #03 pc 0000000000017968 /system/lib64/libpng.so (png_push_read_IDAT480) native: #04 pc 0000000000016c60 /system/lib64/libpng.so (png_process_data124) 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_ptrSkStreamRewindable, std::__1::default_deleteSkStreamRewindable , _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 解码在后台线程完成不会再造成卡顿