简体   繁体   English

具有合成绑定和可空性的 Kotlin 视图

[英]Kotlin views with synthetic binding and nullability

I've noticed that when using Kotlin's synthetic binding, the view returned is non null (Kotlin will return View! ).我注意到当使用 Kotlin 的合成绑定时,返回的视图是非空的(Kotlin 将返回View! )。 But this doesn't make much sense to me, since findCachedViewById can actually return null results, meaning that views can actually be null.但这对我来说意义不大,因为findCachedViewById实际上可以返回空结果,这意味着视图实际上可以为空。

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;
}

So why are they not optional in this case?那么为什么在这种情况下它们不是可选的呢? Why doesn't Kotlin simply return View?为什么 Kotlin 不直接返回View? when using synthetic binding, so that developers would be forced to check nullability when dealing with views?使用合成绑定时,开发人员在处理视图时将被迫检查可空性?

Maybe it's just because I'm new to Kotlin, but I think this is a bit counter intuitive, since the variable is not optional but we are still supposed to check if the View is in fact not null.也许这只是因为我是 Kotlin 的新手,但我认为这有点违反直觉,因为变量不是可选的,但我们仍然应该检查视图是否实际上不为空。

So in this case, does it make sense to do something like the code below?那么在这种情况下,像下面的代码那样做有意义吗?

view?.let {
    // handle non null view here
}

I figured it out, I always find the correct SO question right after I post mine:)我想通了,我总是在发布我的问题后立即找到正确的 SO 问题:)

The single exclamation point following the View does not actually mean that the view can not be null like I expected. View后面的单个感叹号实际上并不意味着视图不能像我预期的那样为 null。

This answer to another question essentially answers my exact question. This answer to another question基本上回答了我的确切问题。 The View , when using synthetic binding, can actually be null, but we can't know for sure, hence the single exclamation mark. View在使用合成绑定时实际上可以为 null,但我们无法确定,因此只有一个感叹号。

So it's safe to assume that the code I posted above - using ?.let{...} is perfectly acceptable way of dealing with views when you are not sure if they are already initialised when accessing them.因此,可以安全地假设我在上面发布的代码 - 使用?.let{...}是处理视图的完全可接受的方式,当您不确定它们在访问它们时是否已经初始化时。

The cases where views might be null are very rare, but it can happen.视图可能为空的情况非常罕见,但它可能会发生。

As you pointed out already, a single exclamation mark does not mean that it's not null, but rather that it's a Java platform type and the compiler doesn't know if it's nullable or not.正如您已经指出的那样,单个感叹号并不意味着它不是空的,而是它是一种 Java 平台类型,编译器不知道它是否可以为空。

I think what you have suggested is fine, although it fails silently in the actual case of a null which might not actually be what you want.我认为你的建议很好,尽管它在 null 的实际情况下默默地失败了,这实际上可能不是你想要的。

Let's say you tried to call your view in onCreateView and forgot that it will not be initialised yet.假设您试图在 onCreateView 中调用您的视图,但忘记了它尚未初始化。 The fragment will not behave as expected but it won't produce a meaningful error to help you debug the issue.该片段不会按预期运行,但不会产生有意义的错误来帮助您调试问题。

I'm still trying to settle on one solution or another myself but I would suggest either explicitly handling the case of a null:我仍在尝试自己解决一个或另一个解决方案,但我建议要么显式处理 null 的情况:

view?.let {
    //...
} ?: throwExceptionIfDebugElseLogToCrashlytics()

Or decide that this time you actually want it to throw the NullPointerException in which case I would suggest:或者决定这次你真的希望它抛出 NullPointerException 在这种情况下我建议:

view!!.let {
    //...
}

The latter doesn't bloat your code for what "should" be an impossible edge case and it doesn't fail silently, but it still makes it clear to a reader that view could be null.后者不会因为“应该”是不可能的边缘情况而使您的代码膨胀,并且它不会悄无声息地失败,但它仍然让读者清楚地知道视图可能为空。 Obviously the,.显然,。 is not needed by the compiler, it is just there to make the chosen strategy for dealing with platform types more explicit.编译器不需要,它只是为了使处理平台类型的选择策略更加明确。

Actualy null pointer exception can happen for synthetic view bindings, if you try to access view from listener out of context of an activity or view, or in lambdas.如果您尝试在活动或视图的上下文之外或在 lambda 中从侦听器访问视图,则合成视图绑定实际上可能会发生空指针异常。

The problem is in lambda, and Frantisek have post about it here:https://stackoverflow.com/posts/comments/115183445?noredirect=1问题出在 lambda 中,Frantisek 在这里发布了相关信息:https ://stackoverflow.com/posts/comments/115183445?noredirect=1

The idea is that xml layouts in Android are pretty static and in order to use synthetic views, you must create a direct import of the parsed layout:这个想法是 Android 中的 xml 布局是相当静态的,为了使用合成视图,您必须创建一个已解析布局的直接导入:

import kotlinx.android.synthetic.main.activity_main.*

So there are no real-life, non-magic scenarios where the View would be null.因此,在现实生活中,不存在View为空的非魔法场景。 Unless you choose the wrong synthetic layout, but then you will get the crash on first run.除非你选择了错误的合成布局,否则你会在第一次运行时崩溃。

That said, it will of course break if you modify the view on runtime, removing Views etc. But again, this is not the default usage for synthetic Views and requires a different approach.也就是说,如果您在运行时修改视图、删除Views等,它当然会中断。但同样,这不是合成Views的默认用法,需要不同的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM