简体   繁体   中英

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! ). But this doesn't make much sense to me, since findCachedViewById can actually return null results, meaning that views can actually be 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;
}

So why are they not optional in this case? Why doesn't Kotlin simply return 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.

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:)

The single exclamation point following the View does not actually mean that the view can not be null like I expected.

This answer to another question essentially answers my exact question. The View , when using synthetic binding, can actually be null, but we can't know for sure, hence the single exclamation mark.

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.

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.

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.

Let's say you tried to call your view in onCreateView and forgot that it will not be initialised yet. 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:

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

Or decide that this time you actually want it to throw the NullPointerException in which case I would suggest:

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.

The problem is in lambda, and Frantisek have post about it here: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:

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

So there are no real-life, non-magic scenarios where the View would be null. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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