我最近在我的 Android 项目中启用了严格收缩器,以积极删除未使用的资源,如官方文档中所述https://developer.android.com/build/shrink-code#strict-reference-checks
但是,启用它后,每当我尝试打开包含 MotionLayout 的屏幕时,我的应用程序就会开始崩溃,并出现以下错误:
Caused by: android.content.res.Resources$NotFoundException: Unable to find resource ID #0x7f0a03f0
at android.content.res.ResourcesImpl.getResourceTypeName(ResourcesImpl.java:316)
at androidx.constraintlayout.motion.widget.MotionScene$Transition.fill(MotionScene.java:978)
at androidx.constraintlayout.motion.widget.MotionScene.load(MotionScene.java:1090)
at androidx.constraintlayout.motion.widget.MotionLayout.init(MotionLayout.java:3840)
at androidx.constraintlayout.motion.widget.MotionLayout.<init>(MotionLayout.java:1124)
at com.mypackage.MyViewBinding.inflate(MyViewBinding.java:102)
at com.mypackage.MyView.<init>(MyView.kt:37)
发生崩溃的原因是 MotionLayout 依赖反射来处理其过渡和关键帧,这会导致使用严格收缩器时出现问题。具体来说,
MotionLayout
使用反射来初始化其内部KeyFrames.java
文件中的关键帧:
sKeyMakers.put(KeyAttributes.NAME, KeyAttributes.class.getConstructor())
sKeyMakers.put(KeyPosition.NAME, KeyPosition.class.getConstructor())
sKeyMakers.put(KeyCycle.NAME, KeyCycle.class.getConstructor())
sKeyMakers.put(KeyTimeCycle.NAME, KeyTimeCycle.class.getConstructor())
sKeyMakers.put(KeyTrigger.NAME, KeyTrigger.class.getConstructor())
由于代码中未显式引用这些资源 ID,因此严格收缩器会认为它们未使用并删除它们。当 MotionLayout 尝试在运行时访问这些资源时,这会导致
Resources$NotFoundException
。
解决方案
为了防止收缩器删除必要的资源 ID,请创建一个 keep.xml 文件并使用 tools:keep 属性指定 MotionLayout 场景中使用的 ID。例如:
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@+id/beforeCrack,@+id/afterCrack,@+id/start"
tools:shrinkMode="strict" />
将此文件放入您的 res 目录中。它确保所有指定的资源保留在最终版本中并且可供 MotionLayout 使用。