5

I find a lot of arguments have the error

Type mismatch
required: FragmentActivity
found: FragmentActivity?

I'm not sure of what's the best way to address this problem. Currently, I wrap the line in a variable?.let{ statement }

meViewModel = ViewModelProviders.of((iMainActivity as Fragment).activity, vmf).get(MeViewModel::class.java) }

into

val fragmentActivity = (iMainActivity as Fragment).activity

fragmentActivity?.let 
{ 
   meViewModel = ViewModelProviders.of(fragmentActivity, vmf).get(MeViewModel::class.java) 
}

is it the right way to approach this

ir2pid
  • 5,604
  • 12
  • 63
  • 107

2 Answers2

5

Short answer: Yes.

This means that the compiler is not sure if s.th. is !=null. If you are sure that it is not null you can also use:

val fragmentActivity = (iMainActivity as Fragment).activity!!

That gives you FragmentActivity instead of FragmentActivity? and you dont need the ?.let{}

Keep in mind that that might throw a NPE, while the

fragmentActivity?.let { fragment ->
   meViewModel = ViewModelProviders.of(fragment, vmf).get(MeViewModel::class.java) 
}

would simply not execute the block within .let{}, which is often less harmful then a NPE. See https://kotlinlang.org/docs/reference/null-safety.html for more.

leonardkraemer
  • 6,573
  • 1
  • 31
  • 54
  • IMHO is the bang operator (`!!`) never a good idea to use, except of unit tests. – rekire Oct 23 '18 at 18:34
  • 1
    Or for interacting with java api that is not annotated with @notnull – leonardkraemer Oct 23 '18 at 18:39
  • @rekire, wouldn't `!!` be better option in this case? With `?.let` here, we would get issue with view model consistency or exception when accessing viewmodel. So while the real problem is fragmentActivity being null, we may be end up thinking viewmodel has issues and start looking for bugs in viewmodel instead. – Thupten Aug 22 '19 at 15:29
  • @Thupten to be honest I don't get your point. From my experience the context get more often lost than you except so an extra check with a let is always a good idea. I never faced any bugs or crashes related with `let`. If you think that your "bug" would be to handle the null case instead of crashing you could consider to log the fact by adding the elvis operator and log something. `fragmentActivity?.let { ... } ?: println("yikes it was null!")` – rekire Aug 23 '19 at 06:54
1

Short answer: Yes.

With ?.let you can be sure that the value will be non null, so you have the null safety you would expect. Just keep in mind that in some cases you cannot use the smartcast which you did in your code above.

Smart casts [...] don't work on var properties, and they always work on local variables (val and var). They also don't work on val properties with a custom getter, because val doesn't mean final in Kotlin.

Quote from Marko Topolnik in the comments.

This is because, in a rare edge case, the value could be changed by a different thread. You will get a compile error so that is prevented too. In that case you would need to use the implicit it or define an own alias like here:

fragmentActivity?.let { fragment ->
   meViewModel = ViewModelProviders.of(fragment, vmf).get(MeViewModel::class.java) 
}
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
rekire
  • 47,260
  • 30
  • 167
  • 264