The API is android, but the question itself isn't,...
# getting-started
r
The API is android, but the question itself isn't, feels more like a basic Kotlin question. I have this API to implement: https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContract by inheritance. The
parseResult
demands a non-null return value - however,
null
is a possible result I may get in there. How do I wrap the
null
into a non-null value, so the compiler is happy with me?
j
You can just make a wrapper:
Copy code
data class CreateFooResult(val foo: Foo?)
But more idiomatic would be to make the semantics of what a
null
result means a bit clearer, e.g. like
Copy code
sealed class CreateFooResult {
  object Aborted : CreateFooResult()
  data class Success(val foo: Foo) : CreateFooResult()
}
or whatever your situation is. You might even find out that you'd really like to distinguish between e.g.
resultCode == Activity.RESULT_CANCEL
and
resultCode == Activity.RESULT_OK && intent?.data == null
or somesuch (when one means that the user aborted the process and the other that there's some other reason)
👍 1
r
null is actually allowed if your generic output type
O
is a nullable type (but using a descriptive result type will be clearer)
r
The abstract class he's implementing marks the return value of
parseResult
as
@NotNull
. So whatever is calling it in the android system is going to fail nastily if he returns null there.
m
Might consider using the Java 8 Optional class.
👍 1
r
I always assumed that one's broken?
Nothing
isn't a valid type here?
Copy code
class PickCompanionDevice<T: Parcelable> : ActivityResultContract<IntentSender, CompanionDeviceResult<T>>() {
    override fun createIntent(context: Context, input: IntentSender): Intent {
        val req = IntentSenderRequest.Builder(input).build()
        return ActivityResultContracts.StartIntentSenderForResult().createIntent(context, req)
    }

    override fun parseResult(resultCode: Int, intent: Intent?): CompanionDeviceResult<T> {
        val res = ActivityResultContracts.StartIntentSenderForResult().parseResult(resultCode, intent)
        val device = res.data?.getParcelableExtra<T>(CompanionDeviceManager.EXTRA_DEVICE)
        return if (device == null) {
            CompanionDeviceResult.NothingSelected
        } else {
            CompanionDeviceResult.Selected(device)
        }
    }
}

sealed class CompanionDeviceResult<T> {
    object NothingSelected: CompanionDeviceResult<Nothing>()
    data class Selected<T>(val device: T): CompanionDeviceResult<T>()
}
Complains about
Copy code
Type mismatch.
Required:
CompanionDeviceResult<T>
Found:
CompanionDeviceResult.NothingSelected
ah, gotta be covariant.
m
I haven’t used the Java 8 Optional just Guava’s, but I haven’t heard about it being broken. You do need to enable the Java 8 desugaring to use it on Android though. For the CompanionDeviceResult, I think you need to bound the T to Any and make it an out.
r
Yup, made it an
out
, no need for the
Any
part though.