0
votes

I am new to Kotlin. I have an android project which I opted to convert to kotlin. This is my piece of code.

import com.beardedhen.androidbootstrap.BootstrapButton
class EndTrip : AppCompatActivity(){
internal var endtrip: BootstrapButton ?=  null

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_end_trip)
endtrip.setOnClickListener(View.OnClickListener {
//Some code here
}
}
}

But I get this error on the endtrip

Smart cast to BootsrapButton is impossible because endtrip is mutable property that have changed by this time

A similar question has been answered here but i cant figure out the solution. I am using beardedhen Android Bootstrap Library. Thank you.

4

4 Answers

3
votes

The error tell you that you cannot guarantee that endtrip is not null at that line of code. The reason is that endtrip is a var. It can be mutated by other thread, even if you do a null check just before you use that variable.

Here is the official document's explanation:

Note that smart casts do not work when the compiler cannot guarantee that the variable cannot change between the check and the usage. More specifically, smart casts are applicable according to the following rules:

  • val local variables - always;
  • val properties - if the property is private or internal or the check is performed in the same module where the property is declared. Smart casts aren't applicable to open properties or properties that have custom getters;
  • var local variables - if the variable is not modified between the check and the usage and is not captured in a lambda that modifies it;
  • var properties - never (because the variable can be modified at any time by other code).

The simplest solution is to use safe call operator ?.

endtrip?.setOnClickListener(View.OnClickListener {
    //Some code here
}

Suggested reading: In Kotlin, what is the idiomatic way to deal with nullable values, referencing or converting them

0
votes

val is the static, var is the mutable. kotlin prefers everything static even more so in the place you called it.

Just to clarify a little, Kotlin only really likes for you to use var inside a method, it doesn't like it up in the main. It wants val up there.

val is an immutable variable var is mutable.

0
votes

I have figured out the problem. I removed the global declaration of endtrip and initialized it in the onCreate method as below.

import com.beardedhen.androidbootstrap.BootstrapButton
class EndTrip : AppCompatActivity(){

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_end_trip)
 var endtrip: BootstrapButton = findViewById(R.id.endtrip) as BootstrapButton
endtrip.setOnClickListener(View.OnClickListener {
//Some code here
}
}
}

But my worry is what if i want to use a variable in other methods?

0
votes

The reason why you are receiving that error is due to smart casting and the use of var. var is mutable, so at any point in your code, it can be changed. Kotlin cannot guarantee that, the value that endtrip will be changed to can be casted to BootstrapButton hence the error. In the documentation under smart casts, it lists various instances when smart casting can't be possible. You can find them here.

To make your code work you will have to change it to this

val endtrip: BootstrapButton ?=  null

With this, Kotlin is rest assured that your endtrip variable won't change and can cast it to BootstrapButton successfully.

Edit: Since you want to reassign endtrip, you could do something like this:

var endtrip: BootstrapButton ?= null
val immutableEndtrip = endtrip // you can definitely use a different variable name

if(immutableEndtrip !=null)
{
endtrip = findViewById(R.id.endtrip) as BootstrapButton
}