Kanj
Kanj

Reputation: 410

Why are non-null type properties of class obtained from WeakReference.get() changing to nullable

I am trying to write a Handler in an Activity that needs a reference to the activity. If I write like this

class MainActivity : AppCompatActivity() {
    private val mHandler = MainActivityHandler(this)

    class MainActivityHandler(val activity: MainActivity) : Handler() {
        override fun handleMessage(msg: Message?) {
            when(msg?.what) {
                MSG_CHANGE_TEXT -> {
                    activity.tv_logged.setText(R.string.title_main)
                    activity.mHandler.sendMessageDelayed(obtainMessage(SOMETHING), 3000)
                }
                // ...
            }
        }
    }
}

This code compiles and works as expected. But if I try to pass a weak reference to the activity like this

class MainActivity : AppCompatActivity() {
    private val mHandler = MainActivityHandler(WeakReference(this))

    class MainActivityHandler(val activityRef: WeakReference<MainActivity>) : Handler() {
        private val activity
            get() = activityRef.get()

        override fun handleMessage(msg: Message?) {
            when(msg?.what) {
                MSG_CHANGE_TEXT -> {
                    activity?.tv_logged.setText(R.string.title_main)
                    activity?.mHandler.sendMessageDelayed(obtainMessage(SOMETHING), 3000)
                }
                // ...
            }
        }
    }
}

Now the compiler complains that tv_logged and mHandler are nullable receiver type and need to be accessed using ?. I can understand that the val activity: MainAcitivity? inside the handler is nullable because it comes from WeakReference.get() but how come the properties in MainActivity are also nullable?

Upvotes: 0

Views: 65

Answers (2)

Kanj
Kanj

Reputation: 410

I understood this when I read the whole text at https://kotlinlang.org/docs/reference/null-safety.html#safe-calls

This has nothing to do with WeakReference as I suspected. It happens because safe call operator returns a nullable type even when accessing non-nullable type properties. (The doc doesn't really specify this as explicitly and clearly.)

Upvotes: 0

Dishonered
Dishonered

Reputation: 8841

Its because the return type of activity?.tv_logged is (assuming its a TextView ) , TextView? . In Kotlin docs , where an alternative is proposed to checking null via if condition

Your second option is the safe call operator, written ?. b?.length This returns b.length if b is not null, and null otherwise. The type of this expression is Int? .

To perform a certain operation only for non-null values, you can use the safe call operator together with let:

 activity?.let{ //access activity via `it`}

Upvotes: 1

Related Questions