В этой статье я поделюсь своим опытом перехода от onActivityResult() к Contract.
Краткое резюме статьи на Хабре и личный опыт.
Рассматриваю пример когда существует активити которое задает вопрос хотите ли вы выйти из аккаунта? и все что оно делает для нас это отвечает на вопрос да или нет? Соответственно нам нужно получить одну булиеву переменную.
Как я делал это раньше?
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.exitButton.setOnClickListener {
startActivityForResult(
Intent(requireContext(), ExitActivity::class.java),0
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == AppCompatActivity.RESULT_OK) {
if (data?.getBooleanExtra(App.IS_SIGN_OUT, false) == true) {
// exit fun
}
}
}
Время onActivityResult подходит к концу, сейчас этот метод помечен как deprecated и есть вероятность что в будущих версиях андроид перестанет поддерживаться вовсе.
К нам на помощь спешат так называемые "контракты"!
И так как быстро и безболезненно заменить onActivityResult на свежий и контракт? Все очень просто. Вместо onActivityResult реализуем вот такой функционал:
private val signOutLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data
if (data?.getBooleanExtra(App.IS_SIGN_OUT, false) == true) {
// exit fun
}
}
}
чтобы запустить лаунчер нужно выполнить не хитрую функцию:
signOutLauncher.launch(Intent(requireContext(), ExitActivity::class.java))
Код стал более аккуратным и мы избавились от Deprecated, но это еще не все, есть еще один не плохой плюс в контрактах, мы можем упростить код и сделать его переиспользываемым.
Для этого нужно создать класс контракт.
class SignOutContract : ActivityResultContract<String, Boolean>() {
override fun createIntent(context: Context, input: String): Intent {
return Intent(context, PopupActivity::class.java)
.putExtra("my_key", input)
}
override fun parseResult(resultCode: Int, intent: Intent?): Boolean = when {
resultCode != Activity.RESULT_OK -> false
else -> intent?.getBooleanExtra(App.IS_SIGN_OUT, false) ?: false
}
override fun getSynchronousResult(
context: Context,
input: String
): SynchronousResult<Boolean>? {
return if (input.isEmpty()) SynchronousResult(false) else null
}
}
И собственно инициализация слушателя и вызов этого контракта:
val activityLauncher = registerForActivityResult(SignOutContract()) { result ->
// используем result (в нашем случаае это Boolean)
if (result) {
// exit fun
}
}
activityLauncher.launch("In yor activity needs string")
Теперь наш код может быть переиспользован и вызов этой активности стал в разы короче!