对于 @hide 最简单的比喻就是将 Android SDK 想象成一座冰山,在文档中的只是你能看到的部分。
Android SDK 中的类(Activity, AsyncTask, AlarmManager...)都是普通的 Java 类。因此,就可见性而言,它们受到的约束和其他 Java 类是一样的:
- public:也就是我们在文档中能看到的大部分内容。
- private
- 'package-private':也就是不加限定。
对于成员,比如属性和方法,也可以是 protected,也就是对子类可见。
在理想的情况下,这些就已经足够了。
但是,这样就意味着所有 public 和 protected 的部分都是对外可见 API 的一部分。但在某些情况下,Android 框架的开发人员需要可见性为 public 或 protected 的类或成员,但又不希望这些方法成为开发者可用的 API。
这就是 @hide 的用处了。
当你在 build.gradle 文件中指定 compileSdkVersion 为 27 时,也就是告诉了构建系统:
- 进入 $ANDROID_SDK/platforms/android-27/ 目录。
- 找到该目录中的 android.jar 文件。
- 把这个 JAR 添加到编译时类路径中。
应 javac 编译你的 Java 代码时,会根据这个 android.jar 的内容来解析所有对 Android SDK 中成员的引用。但这个 android.jar 不会打包到你的应用中,而是在运行时有另一个 android.jar 被链接到应用的进程中。
编译时和运行时 android.jar 的主要区别有两点:
- 编译时的 android.jar 不包含真正的方法实现。
- 编译时的 android.jar 不包含被 @hide 标记的类或成员。
在 Android 8.1 版本的 Activity 中,@hide 就出现了 45 次,这还只是这一个类。
可能 Android 开发者会比较有探索精神,如果被告知不能干什么,就会有人想绕过这个限制。但使用这些方法一直是有风险的。Google 这么多年在保证 API 稳定和兼容性方面做得还不错,但这不适用于被 @hide 标记的内容。因此可能有的问题:
- 隐藏的 API 在未来的 Android 版本中可能被删除。
- 可能会被修改方法签名或字段类型。
- 设备制造商还可能会删除或修改隐藏的 API,这可能会影响这部分设备。
即使没有完全禁止隐藏 API 的使用,上面的这些问题也可能在任何时候发生。因此,总的来说,普通开发者最好还是避免使用隐藏 API,风险往往大于收益。