我注意到在使用Kotlin的合成绑定时,返回的视图为非null(Kotlin将返回View!
)。但这对我来说没有多大意义,因为findCachedViewById
实际上可以返回null结果,这意味着视图实际上可以为null。
public View _$_findCachedViewById(int var1) {
if(this._$_findViewCache == null) {
this._$_findViewCache = new HashMap();
}
View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1));
if(var2 == null) {
View var10000 = this.getView();
if(var10000 == null) {
return null;
}
var2 = var10000.findViewById(var1);
this._$_findViewCache.put(Integer.valueOf(var1), var2);
}
return var2;
}
那么为什么在这种情况下它们不是可选的呢?为什么Kotlin在使用合成绑定时只返回View?
,这样开发人员在处理视图时会被迫检查可空性?
也许只是因为我是Kotlin的新手,但我认为这有点反直觉,因为变量不是可选的,但我们仍然应该检查View是否实际上不是null。
所以在这种情况下,做下面的代码是否有意义?
view?.let {
// handle non null view here
}
答案 0 :(得分:6)
我想通了,我发帖后总能找到正确的SO问题:)
View
之后的单个惊叹号实际上并不意味着视图不能像我预期的那样为空。
另一个问题的answer基本上回答了我的确切问题。使用合成绑定时,View
实际上可以为空,但我们无法确定,因此是单个感叹号。
因此,可以安全地假设我在上面发布的代码 - 使用?.let{...}
是完全可以接受的方式来处理视图,当您不确定它们是否已经在访问时已经初始化。
视图可能为null的情况非常罕见,但可能会发生。
答案 1 :(得分:1)
正如您已经指出的,单个感叹号并不意味着它不为空,而是它是Java平台类型,并且编译器不知道它是否可以为空。
我认为您的建议很好,尽管在实际为null的实际情况下它默默地失败了,而这实际上可能并不是您想要的。
假设您尝试在onCreateView中调用视图,但忘记了它尚未初始化。该片段将无法正常运行,但不会产生有意义的错误来帮助您调试问题。
我仍在尝试自己解决一个问题,但我还是建议明确处理null的情况:
table * {
border: none;
}
或者决定这次您实际上希望它抛出NullPointerException,在这种情况下,我建议:
view?.{
//...
} ?: throwExceptionIfDebugElseLogToCrashlytics()
后者不会因为“应该”是不可能的边缘情况而使您的代码膨胀,并且不会默默地失败,但是它仍然使读者清楚地看到视图可能为空。显然是!编译器不需要它,只是使所选择的用于处理平台类型的策略更加明确。
答案 2 :(得分:0)
我们的想法是Android中的xml布局非常静态,为了使用合成视图,您必须创建直接导入已解析的布局:
import kotlinx.android.synthetic.main.activity_main.*
因此,没有真实的,非魔法的场景,View
将为空。除非你选择了错误的合成布局,否则你将在第一次运行时遇到崩溃。
也就是说,如果你在运行时修改视图,删除Views
等,它当然会中断。但同样,这不是合成Views
的默认用法,需要采用不同的方法。
答案 3 :(得分:0)
如果尝试从活动或视图的上下文之外或在lambda中从侦听器访问视图,则合成视图绑定可能会发生空指针异常。
问题出在lambda上,Frantisek在这里发表了有关此问题的文章: https://stackoverflow.com/posts/comments/115183445?noredirect=1