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 沟通一下了。

最后

代码出错了,关键是要仔细查看日志。能够仔细地查看日志,就离解决问题很近了。

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