Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
}
like image 348
Guy Avatar asked Mar 14 '18 11:03

Guy


2 Answers

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.

like image 200
Guy Avatar answered Nov 06 '22 08:11

Guy


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.

like image 1
Mike Simpson Avatar answered Nov 06 '22 07:11

Mike Simpson