片段:getContext 与 requireContext
TLDR:仅当您确定片段已附加到其主机(onResume、onViewCreated 等)时才使用 requireContext。
问题
Android 团队在 27.1.0 版的支持库中为一些 SDK 方法添加了 NonNull 和 Nullable 注释。这一更改会导致出现如上图所示的警告和错误。
他们为什么这么做?
乍一看,这似乎给 Android 应用开发带来了越来越多的麻烦。但实际上,这些注解有助于我们降低崩溃率。
当 fragment 未附加到其主机时,getContext 可能会返回 null。我们来看两个例子。
@Override
public void onResume() {
super.onResume();
Resources resources = getContext().getResources();
}
第一个示例向我们展示了,只要片段附加到其主机(例如在 onResume 中),就可以安全地使用 getContext 而无需进行可空性检查。
@Override
public void onResume() {
super.onResume();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
final Resources resources = getContext().getResources();
}
}, TimeUnit.SECONDS.toMillis(5));
}
第二个漏洞揭示了潜在的 NullPointerException。如果 5 秒后 fragment 仍未连接到主机,应用程序就会崩溃。
因此,getContext Nullable 注解可以避免像第二个示例中那样的错误。但它会在 Java 中的第一个示例中引发无用的警告,并在 Kotlin 中引发错误。
我们应该如何解决这个问题?
首先我们应该修复潜在的错误。
- 找到在某个时间点可以分离片段的所有位置
- 按照下面的示例更改代码
在 Java 中:
Context context = getContext();
if (context == null) {
// Handle null context scenario
} else {
// Old code with context
}
在 Kotlin 中:
val context: Context = this.context ?: return // or if block
最后,用 requireContext() 替换其余部分,它会返回非空上下文,而不是 getContext()。但请记住,如果 fragment 未连接到其宿主,requireContext() 会抛出异常。因此,您应该根据 fragment 的生命周期使用 requireContext()。
错误修复
在 Java 中:
1.
// requireContext() does the same
Context context = getContext();
if (context == null) {
throw new IllegalStateException("");
}
2.
// Warning supressing only hides the real problem
private void doSomething(@NonNull final Context context) {
}
@Override
public void onResume() {
super.onResume();
//noinspection ConstantConditions
doSomething(getContext());
}
在 Kotlin 中:
// It is similar to requireContext() but with NullPointerException
val context: Context = context!!
其他类似方法
- getActivity 与 requireActivity
- getHost 与 requireHost
- getFragmentManager 与 requireFragmentManager