好久没有写这个系列了,感觉还是需要把日常开发中遇到的问题做一个记录总结,因为有些问题我当时遇到时,搜都搜不到,只能慢慢摸索。帮助他人的同时也能给自己留个备忘录。话不多说,凡是近一年的奇怪问题,我想起一个会补充一个。
1.适配Android 12应用启动画面
如果windowSplashScreenAnimatedIcon
设置的是静态图片,即使你用的是矢量图,开屏是图片还是会模糊。最后发现使用动态矢量图就清晰了。。。可以用标签包裹原先的静态图,示例如下:
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector .../>
</aapt:attr>
</animated-vector>
也不知道具体是什么原因,只是当我发现Gmail的启动画面是正常的时,怀疑是不是需要用动态矢量图。结果一试发现果然正常了。
上线后发现了另一个问题,个别Android 12设备上出现了三种崩溃,由多到少排序如下:
Fatal Exception: java.lang.IllegalArgumentException: Activity client record must not be null to execute transaction item
at android.app.servertransaction.ActivityTransactionItem.getActivityClientRecord(ActivityTransactionItem.java:85)
at android.app.servertransaction.ActivityTransactionItem.getActivityClientRecord(ActivityTransactionItem.java:58)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:43)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'com.android.server.wm.DisplayContent com.android.server.wm.WindowContainer.getDisplayContent()' on a null object reference
at android.os.Parcel.createExceptionOrNull(Parcel.java:2432)
at android.os.Parcel.createException(Parcel.java:2410)
at android.os.Parcel.readException(Parcel.java:2393)
at android.os.Parcel.readException(Parcel.java:2335)
at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2377)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1808)
at android.app.Activity.startActivityForResult(Activity.java:5506)
at androidx.activity.ComponentActivity.startActivityForResult(SourceFile:2)
at android.app.Activity.startActivityForResult(Activity.java:5464)
at androidx.activity.ComponentActivity.startActivityForResult(SourceFile:1)
at android.app.Activity.startActivity(Activity.java:5854)
at android.app.Activity.startActivity(Activity.java:5807)
下面这个都是Android12的小米手机,机型型号:Redmi 9T,Redmi Note 9 Pro,Redmi Note 11 Pro 5G,Poco M2 Pro:
Fatal Exception: java.lang.IllegalArgumentException: reparent: can't reparent to null, mParent is nullWindow{37a85c8 u0 Splash Screen com.xxx}
at android.os.Parcel.createExceptionOrNull(Parcel.java:2430)
at android.os.Parcel.createException(Parcel.java:2410)
at android.os.Parcel.readException(Parcel.java:2393)
at android.os.Parcel.readException(Parcel.java:2335)
at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:2721)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1745)
at android.app.Activity.startActivityForResult(Activity.java:5482)
at androidx.activity.ComponentActivity.startActivityForResult(SourceFile:2)
at android.app.Activity.startActivityForResult(Activity.java:5440)
at androidx.activity.ComponentActivity.startActivityForResult(SourceFile:1)
at android.app.Activity.startActivity(Activity.java:5826)
at android.app.Activity.startActivity(Activity.java:5779)
记得当时统计到一天会崩溃2次左右,这三种崩溃总计影响了近80位用户。
Android 13上会出现崩溃如下:
Fatal Exception: java.lang.NullPointerException: Attempt to invoke direct method 'void android.view.SurfaceControl.checkNotReleased()' on a null object reference
at android.view.SurfaceControl.-$$Nest$mcheckNotReleased()
at android.view.SurfaceControl$Transaction.checkPreconditions(SurfaceControl.java:2896)
at android.view.SurfaceControl$Transaction.hide(SurfaceControl.java:3079)
at android.app.ActivityThread.syncTransferSplashscreenViewTransaction(ActivityThread.java:4359)
at android.app.ActivityThread.-$$Nest$msyncTransferSplashscreenViewTransaction()
at android.app.ActivityThread$1.onDraw(ActivityThread.java:4336)
at android.view.ViewTreeObserver.dispatchOnDraw(ViewTreeObserver.java:1132)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:4805)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4572)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3758)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2458)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9466)
这个总共崩溃14次,对于大多数用户是Android 13系统来说,相对比较低。
后面我也查询到了相关问题:
- java.lang.IllegalArgumentException: Activity client record must not be null to execute transaction item
- App crashing by NPE or IllegalArgumentException on WindowContainer#reparent() during system splash screen exit animation
- Crash: Attempt to invoke direct method ‘void android.view.SurfaceControl.checkNotReleased()’ on a null object reference
结论是Android 源码中的一个bug,但是另我不解的是当时另外一个产品也做了相关适配,但是没有此类问题。后面对比发现是多了下面这个方法:
getSplashScreen().setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
@Override
public void onSplashScreenExit(@NonNull SplashScreenView splashScreenView) {
splashScreenView.remove();
}
});
加这个目的是原因是个别手机上SplashScreen
和页面过渡时会有淡入淡出的切换动画。为了过渡“无感”,所以加了这个监听方法,在SplashScreen
结束时直接移除。
一开始以为是remove导致的空指针,所以一开始的修复方式是改为隐藏splashScreenView.setVisibility(View.GONE)
,然后上线后发现无效。。。最后只能是删除了这个监听,之后就没有崩溃了。
因为是个别机型个别系统版本的问题,所以也不方便去找这些厂家的源码去一探究竟。所以只能是去线上快速试错,好在此类崩溃不多,否则真是会让人头疼不已。
2. Gson与Gradle
年初将Gradle从7.0.2升到7.2.2后,发现release包运行崩溃了。
Fatal Exception: java.lang.RuntimeException: Missing type parameter.
com.google.gson.reflect.TypeToken.getSuperclassTypeParameter (TypeToken.java:84)
com.google.gson.reflect.TypeToken.<init> (TypeToken.java:62)
看到异常报到了Gson上面,所以我就去gson项目下搜了一下相关异常,结果如下:(gson版本是2.8.5)
相关问题:
- Missing type parameter RuntimeException
- R8 FullMode in AGP 7.0.0-beta01 transforming ParameterizedType implementations to Class
原因是R8 3.0版本开始从未在完整模式下(full mode)与-keep规则匹配的项目中删除通用签名。此更改的动机是避免在程序中保留所有通用签名,而通常只需要少数通用签名用于反射。
解决方法,添加混淆配置:
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
3. 静音与投屏
这个是最近出现的问题。项目中的视频在播放时,有段逻辑会触发"取消静音"的操作,这块发生了崩溃,问题代码:
AudioManager mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
Android 13 ,机型:Galaxy Z Flip4 / Galaxy Z Flip3 / Galaxy Z Fold4 ,异常如下:
Fatal Exception: java.lang.SecurityException: Permission required to call setVolumeKeyEvent: Neither user 10188 nor current process has android.permission.CONFIGURE_WIFI_DISPLAY.
at android.os.Parcel.createExceptionOrNull(Parcel.java:3023)
at android.os.Parcel.createException(Parcel.java:3007)
at android.os.Parcel.readException(Parcel.java:2990)
at android.os.Parcel.readException(Parcel.java:2932)
at android.media.IAudioService$Stub$Proxy.adjustStreamVolumeWithAttribution(IAudioService.java:4666)
at android.media.AudioManager.adjustStreamVolume(AudioManager.java:971)
at android.media.AudioManager.setStreamMute(AudioManager.java:1506)
Caused by android.os.RemoteException: Remote stack trace:
at android.app.ContextImpl.enforce(ContextImpl.java:2359)
at android.app.ContextImpl.enforceCallingOrSelfPermission(ContextImpl.java:2387)
at com.android.server.display.DisplayManagerService$BinderService.setVolumeKeyEvent(DisplayManagerService.java:4566)
at android.hardware.display.DisplayManagerGlobal.setVolumeKeyEvent(DisplayManagerGlobal.java:1196)
at android.hardware.display.DisplayManager.semSetWifiDisplayConfiguration(DisplayManager.java:2489)
提示没有CONFIGURE_WIFI_DISPLAY
权限,但是这个权限只授予系统应用程序。这个权限是允许应用程序配置和连接到Wifi显示器的,通常用做系统无线投屏(Miracast)。
我查到同样机型和系统且能触发这块代码的用户一百多人,目前出现此问题的只有四人。(十天时间)
我能想到的是,用户可能有使用三星系统自带的Smart View来进行投屏。因为使用App同时使用系统投屏功能本就是少数(因为App中有投屏功能),且这个功能不是最近才有的。这样突然集中出现,且都是三星的设备,只能大概率怀疑是手机系统更新后出现的新问题。
目前处理方法只能先加上异常捕获,改为错误上报,持续观察一下。后面有进展了会补充到这里。