
静态分析代码质量开发工具【免费下载链接】error-proneCatch common Java mistakes as compile-time errors项目地址https://gitcode.com/gh_mirrors/er/error-prone点击查看免费下载导读FragmentNotInstantiable 是 Error Pronecom.google.errorprone.bugpatterns.android包中针对 Android 开发的一个内置检查器用于在编译期捕获无法被反射实例化的 Fragment 子类。本文以 FragmentNotInstantiable.md 官方文档为骨架结合 核心实现 与 配套测试 展开帮助你理解该检查的判定规则、底层实现与验证方式并掌握在 Android 工程中如何正确书写 Fragment 子类公开类 公开无参构造器 静态内部类以及如何通过setArguments(Bundle)传递参数避免崩溃。Fragment 为什么必须可被反射实例化Android 框架在发生配置变更configuration change典型场景是屏幕旋转时会销毁当前 Activity/Fragment随后通过Class#newInstance()反射地重新创建Fragment 实例。newInstance()要求满足两个硬性条件类本身必须是public否则反射时无法访问必须存在一个public 的无参nullary构造器。只要其中任一条件不满足运行时就会抛出InstantiationExceptionNoSuchMethodException是其常见子类导致界面恢复失败、应用崩溃。官方文档特别强调强烈建议 Fragment 子类不要声明带参数的构造器。原因在于这些带参构造器在 Fragment 被重新实例化时根本不会被调用——框架只会调用无参构造器。正确的参数传递方式是把参数打包进Bundle用setArguments(Bundle)传入在 Fragment 内通过getArguments()读取。这是 Android 官方推荐的参数传递模式也是该检查背后希望引导的最佳实践。检查规则速览四条硬性要求综合官方文档与源码注解FragmentNotInstantiable的summary一个合法的、可被框架实例化的 Fragment 子类必须同时满足规则违反时的诊断消息片段类必须是publicFragment is not instantiable: a fragment must be public.若为成员内部类必须是staticFragment is not instantiable: a fragment inner class must be static.必须存在无参构造器Fragment is not instantiable: the nullary constructor is missing.无参构造器必须是publicFragment is not instantiable: the nullary constructor must be public.所有消息统一以Fragment is not instantiable:为前缀见源码中的MESSAGE_BASE常量并以句号结尾。实现剖析检查器如何工作检查器的完整实现位于 core/src/main/java/com/google/errorprone/bugpatterns/android/FragmentNotInstantiable.java它实现ClassTreeMatcher即对每一个类声明ClassTree进行匹配。其判定流程可以拆解为以下步骤1. Android 环境门控if (!state.isAndroidCompatible()) { return Description.NO_MATCH; }isAndroidCompatible()的实现见 VisitorState.java它读取 javac 内部选项androidCompatible。也就是说只有在编译命令显式声明目标是 Android例如通过-XDandroidCompatibletrue时该检查才会真正生效。这一门控同样存在于FragmentInjection、ParcelableCreator、BundleDeserializationCast等一批 Android 专项检查中避免在纯 JVM 项目中误报。2. 识别Fragment 子类检查器通过fragmentMatcher判断一个类是否是 Fragment 子类。默认情况下它只认两个基类源码中定义的常量android.app.Fragment框架内置 Fragmentandroid.support.v4.app.Fragmentv4 兼容库版本用于 Android 3.0 之前平台上的应用。匹配逻辑为kindIs(CLASS)anyOf(isSubtypeOf(...))即只要继承自上述任一基类即命中。值得注意的细节源码会显式跳过 Fragment 基类自身的声明fragmentClasses.contains(className)时直接NO_MATCH避免对框架 stub 误报。3. 豁免规则抽象类不检查if (classTree.getModifiers().getFlags().contains(ABSTRACT)) { return Description.NO_MATCH; }抽象 Fragment 子类不会被框架直接实例化因此不参与检查。这与测试中的AbstractFragment、AbstractV4Fragment负例一致。4. 逐条核验四项规则源码按照公开性 → 静态性 → 无参构造器的顺序依次核验每条规则违反时立即返回带对应说明的Description。这里的关键在于当类显式声明了构造器但其中没有无参构造器时才会报nullary constructor is missing若类完全没有声明任何构造器Java 编译器会自动生成一个 public 无参默认构造器因此这种形态天然合法——测试中的MyFragment extends Fragment {}正是据此作为负例。测试用例中的正例与反例配套测试 FragmentNotInstantiableTest.java 使用CompilationTestHelper在编译期断言诊断信息createCompilationTestHelper通过setArgs(ImmutableList.of(-XDandroidCompatibletrue))开启 Android 兼容模式并为android.app.Fragment与android.support.v4.app.Fragment提供 stub 源码。正例应报错覆盖了典型错误形态static class PrivateFragment extends Fragment { // 类非 public public PrivateFragment() {} } public static class PrivateConstructor extends Fragment { // 无参构造器非 public PrivateConstructor() {} } public static class NoConstructor extends Fragment { // 缺少无参构造器 public NoConstructor(int x) {} } public class EnclosingClass { public class InnerFragment extends Fragment { // 成员内部类非 static public InnerFragment() {} } }负例不应报错验证了检查的精确边界非 Fragment 类、抽象 Fragment、具有 public 无参构造器无论是否同时有带参构造器的类、静态内部 Fragment以及接口中隐式为 public static 的内部 Fragment均不会触发诊断。这些用例同时表明只要存在 public 无参构造器额外声明带参构造器并不会触发该检查尽管文档仍建议避免使用带参构造器传参。启用方式、严重级别与抑制FragmentNotInstantiable通过 BugPattern 注解 声明元数据severity WARNING默认作为警告非 ERROR上报tags StandardTags.LIKELY_ERROR属于极大概率是真实错误99.9%但因兼容性原因未设为 ERROR的一类见BugPattern.StandardTags.LIKELY_ERROR的说明altNames {ValidFragment}声明别名ValidFragment用于SuppressWarnings兼容该检查改编自 Android Lint 的同名规则因此别名保留原规则名。它被注册在BuiltInCheckerSuppliers的默认启用集合中BuiltInCheckerSuppliers.java并随 Error Prone 的默认配置一起生效。实际使用中Maven / Gradle引入com.google.errorprone:error-prone作为注解处理器即可默认启用该检查javac 命令行以-Xplugin:ErrorProne -XDandroidCompatibletrue方式接入并显式开启 Android 兼容标志否则检查被门控跳过抑制在类或构造器上使用SuppressWarnings(FragmentNotInstantiable)历史代码也可使用SuppressWarnings(ValidFragment)别名。若需要彻底关闭可在 Error Prone 配置中排除该检查-Xep:FragmentNotInstantiable:OFF。扩展能力自定义 Fragment 基类从源码可见FragmentNotInstantiable的构造函数为protected FragmentNotInstantiable(IterableString additionalFragmentClasses)允许子类注入额外的Fragment 基类名单。测试中的CustomFragmentNotInstantiable正是这样实现的BugPattern(summary Subclasses of CustomFragment must be instantiable ..., severity WARNING) public static class CustomFragmentNotInstantiable extends FragmentNotInstantiable { public CustomFragmentNotInstantiable() { super(ImmutableSet.of(com.google.errorprone.bugpatterns.android.testdata.CustomFragment)); } }也就是说如果你的工程有自己的抽象 Fragment 基类如BaseFragment可以通过继承该检查器并传入自定义类名将同样的可实例化约束推广到整条继承链上。相关正/负例测试positiveCases_custom、negativeCase_custom证明了自定义基类场景下诊断的准确性。小结FragmentNotInstantiable 用一条可反射实例化规则串联起了 Android Fragment 生命周期中极易踩坑的两个问题配置变更后的InstantiationException崩溃以及带参构造器中的参数在重建时丢失。遵循该检查的约束——public 类、public 无参构造器、成员内部类加 static、参数改用setArguments/getArguments——即可让 Fragment 在任意配置变更场景下被框架安全地重新创建。参考文件官方文档docs/bugpattern/android/FragmentNotInstantiable.md检查器实现core/src/main/java/com/google/errorprone/bugpatterns/android/FragmentNotInstantiable.java测试用例core/src/test/java/com/google/errorprone/bugpatterns/android/FragmentNotInstantiableTest.java注解元数据定义annotation/src/main/java/com/google/errorprone/BugPattern.javaAndroid 环境门控check_api/src/main/java/com/google/errorprone/VisitorState.java默认注册表core/src/main/java/com/google/errorprone/scanner/BuiltInCheckerSuppliers.java赞分享静态分析代码质量开发工具【免费下载链接】error-proneCatch common Java mistakes as compile-time errors项目地址https://gitcode.com/gh_mirrors/er/error-prone点击查看免费下载相关推荐Error Prone 的 FragmentInjection 检查在编译期拦截 Android PreferenceActivity 的 Fragment 注入漏洞Error Prone 的 FragmentInjection 检查在编译期拦截 Android PreferenceActivity 的 Fragment静态分析代码质量开发工具Error Prone BundleDeserializationCast 检查识别 Android Bundle 反序列化强转隐患Error Prone BundleDeserializationCast 检查识别 Android Bundle 反序列化强转隐患 当把 Serializa静态分析代码质量开发工具Error Prone AutoValueImmutableFields 检查器让 AutoValue 属性保持深度不可变Error Prone AutoValueImmutableFields 检查器让 AutoValue 属性保持深度不可变 AutoValue 生成的值对象静态分析代码质量开发工具上一篇Plain Craft Launcher 2免费开源Minecraft启动器终极使用指南下一篇5分钟掌握PCL2免费开源Minecraft启动器的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考