基础知识
在 Kotlin 中,其类型系统严格区分一个引用是否可以容纳null。也就是说,一个变量是否可空必须显示声明,对于可空变量,在访问其成员时必须做空处理,否则无法编译通过。
var a: String = "abc" a = null // 编译错误 var b: String? = "abc" //String? 表示该 String 类型变量可为空 b = null // 编译通过
尽管当前kotlin在android项目开发中占比在逐步提高,但是大量开发还是Java代码。供应用层调用的framework代码也是java实现的,所以大量情景下是kotlin和java代码混合开发的。那当kotlin调用Java代码,Java代码是如何定义是否能容纳null呢?
//不为空 @NonNull public final Context requireContext() { Context context = getContext(); if (context == null) { throw new IllegalStateException("Fragment " + this + " not attached to a context."); } return context; } //可为空 @Nullable public Context getContext() { return mHost == null ? null : mHost.getContext(); }
函数参数是否容纳null判断也是同理用@Nullable和@NonNull标记
问题
最近将compileSdkVersion、targetSdkVersion更新到27,然后收到了些编译错误,例如:context is now nullable(context?) instead of non-null, 特别在fragment中的getActivity(),fragmentManager等都有编译报错,扒了下代码查找报错的问题
//报错 tpye mismatch required:context found:context? val viewDialog = AlertDialog.Builder(context) //context参数要求为 @NonNull public Builder(@NonNull Context context) { this(context, resolveDialogTheme(context, 0)); }
//返回的context为 Nullable
@Nullable
public Context getContext() {
return mHost == null ? null : mHost.getContext();
}
```
边缘报错的原因应该一目了然了。
解决
直接告诉变压器context不可能为null,编译时候不去null检查。嗯,现在编译是不报错了,当然造成结果就是一旦为null直接挂了。而且既然API写的是Nullable,那就是存在为null的情况的
builder = AlertDialog.Builder(context!!)
这个是在网上看到的解决方案,大概就是在basefragment中重写getContext()方法,跟1换汤不换药。
override fun getContext(): Context { return super.getContext()!!
}
“`
其实APi27中新加了requireContext()方法,类似还有requireActivity(),requireHost()方法
@NonNull public final Context requireContext() { Context context = getContext(); if (context == null) { throw new IllegalStateException("Fragment " + this + " not attached to a context."); } return context; }
}
“`