Android 開發中遇到的 bug(6)

前言

記錄開發中遇到的 bug,不再讓自己重複地被同樣的 bug 折磨。

正文

1. Android 9.0上通過 Intent 卸載應用無反應

時間:2019年4月27日14:40:33
問題描述:應用已經 target 28,在9.0手機上測試通過 Intent 卸載應用無反應,代碼如下:

Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.setAction("android.intent.action.DELETE");
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse("package:" + mAppInfo.getPackname()));
context.startActivity(intent);

在9.0以下的手機上都是正常的。
解決辦法:
在調用這塊代碼時,查看 log,如下:

2019-04-27 14:30:27.626 17763-17763/? E/PackageInstaller: UninstallerActivity:Uid 10950 does not have android.permission.REQUEST_DELETE_PACKAGES or android.permission.DELETE_PACKAGES

可以看到 PackageInstaller,打出了日誌,提示沒有 android.permission.REQUEST_DELETE_PACKAGES 或者 android.permission.DELETE_PACKAGES。我們知道,通過隱式 Intent,調用的是系統的卸載頁面。
查看一下,9.0的對應源碼,這是地址,可以看到如下代碼:

   if (getMaxTargetSdkVersionForUid(this, callingUid)
                    >= Build.VERSION_CODES.P && AppGlobals.getPackageManager().checkUidPermission(
                    Manifest.permission.REQUEST_DELETE_PACKAGES, callingUid)
                    != PackageManager.PERMISSION_GRANTED
                    && AppGlobals.getPackageManager().checkUidPermission(
                            Manifest.permission.DELETE_PACKAGES, callingUid)
                            != PackageManager.PERMISSION_GRANTED) {
                Log.e(TAG, "Uid " + callingUid + " does not have "
                        + Manifest.permission.REQUEST_DELETE_PACKAGES + " or "
                       + Manifest.permission.DELETE_PACKAGES);

               setResult(Activity.RESULT_FIRST_USER);
               finish();
               return;
            }

從上面的代碼可以看到,確實會檢查是否申請了 Manifest.permission.REQUEST_DELETE_PACKAGES 這個權限。
解決辦法就是在 Manifest.xml 中添加權限:

<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />

2. 使用 Lottie 動畫,線上報出 OOM 的問題

時間:2019年4月27日16:36:07
問題描述:之前在項目中使用過 Lottie 動畫,但使用的並不多;這次的項目卻是大量地使用了 Lottie 動畫。本想着可以不用自定義控件了,提高生產力,卻產生了一個 Top1 的 bug。
錯誤日誌如下

java.lang.OutOfMemoryError
	at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
	at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:683)
	at com.airbnb.lottie.b.b.a(Unknown Source)
	at com.airbnb.lottie.f.b(Unknown Source)
	at com.airbnb.lottie.c.c.c.f(Unknown Source)
	at com.airbnb.lottie.c.c.c.b(Unknown Source)
	at com.airbnb.lottie.c.c.a.a(Unknown Source)
	at com.airbnb.lottie.c.c.b.b(Unknown Source)
	at com.airbnb.lottie.c.c.a.a(Unknown Source)
	at com.airbnb.lottie.c.c.b.b(Unknown Source)
	at com.airbnb.lottie.c.c.a.a(Unknown Source)
	at com.airbnb.lottie.f.draw(Unknown Source)
	at android.widget.ImageView.onDraw(ImageView.java:1058)
	at android.view.View.draw(View.java:15410)
	at android.view.View.buildDrawingCache(View.java:14617)
	at android.view.View.getDisplayList(View.java:14277)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.support.constraint.ConstraintLayout.dispatchDraw(Unknown Source)
	at android.view.View.getDisplayList(View.java:14296)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.view.View.getDisplayList(View.java:14296)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.view.View.draw(View.java:15413)
	at android.view.View.getDisplayList(View.java:14301)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.view.View.draw(View.java:15413)
	at android.widget.FrameLayout.draw(FrameLayout.java:472)
	at android.view.View.getDisplayList(View.java:14301)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.view.View.getDisplayList(View.java:14296)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.view.View.getDisplayList(View.java:14296)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.view.View.getDisplayList(View.java:14296)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.View.draw(View.java:15124)
	at android.view.ViewGroup.drawChild(ViewGroup.java:3309)
	at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3146)
	at android.view.View.draw(View.java:15413)
	at android.widget.FrameLayout.draw(FrameLayout.java:472)
	at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2583)
	at android.view.View.getDisplayList(View.java:14301)
	at android.view.View.getDisplayList(View.java:14343)
	at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1570)
	at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1449)
	at android.view.ViewRootImpl.draw(ViewRootImpl.java:2777)
	at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2643)
	at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2211)
	at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
	at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6637)
	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:814)
	at android.view.Choreographer.doCallbacks(Choreographer.java:614)
	at android.view.Choreographer.doFrame(Choreographer.java:584)
	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:800)
	at android.os.Handler.handleCallback(Handler.java:733)
	at android.os.Handler.dispatchMessage(Handler.java:95)
	at android.os.Looper.loop(Looper.java:146)
	at android.app.ActivityThread.main(ActivityThread.java:5602)
	at java.lang.reflect.Method.invokeNative(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:515)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
	at dalvik.system.NativeStart.main(Native Method)

這些日誌是友盟上統計出來的。但是,這裏面卻沒有指向我自己應用代碼調用的地方。可以關注此 issue
解決辦法:在網上搜索 lottie issue 裏 OutOfMemoryError 的關鍵詞,找到了答案:

重點的解釋是:

I think you may misunderstand the point of Lottie. Lottie is made to render After Effects animations that were created as vectors/shapes. You’re much better off with an mp4 or gif if you’re just creating a png sequence. This issue has nothing to do with Lottie and is just because your animation is 100 sequential pngs that you’re loading into memory.

根據這裏的表述,我們應用中的 lottie 確實使用了大量的 png,這會是一個風險點。

解決辦法:
1,使用 lottie,但減少圖片使用;2,使用原生自定義動畫。第一點需要跟 UI 溝通一下了。

最後

代碼出錯了,關鍵是要仔細查看日誌。能夠仔細地查看日誌,就離解決問題很近了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章