Насколько безопасна регистрация контрактов с ActivityResultRegistry после onResume в Android?

Следующий код дает мне ошибку, так как регистрация происходит после onResume:

      class TempActivity: AppCompatActivity(){
      private lateinit var binding: ActivityTempBinding
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityTempBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.tempBtn.setOnClickListener {
            val a = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
                //SomeCode
            }
            a.launch(
                //SomeIntent
            )
        }

    }

Однако, если я использую activityResultRegistry, я не получаю никаких ошибок. Код

      class TempActivity: AppCompatActivity(){
      private lateinit var binding: ActivityTempBinding
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityTempBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.tempBtn.setOnClickListener {
            val a = activityResultRegistry.register("key", ActivityResultContracts.StartActivityForResult()){
            // SomeCode
            }
            a.launch(
               //Some Intent
            )
        }

    }

Последний код запускается без проблем и запускает соответствующий интент. Я просто хочу знать, насколько безопасен последний и есть ли нежелательное поведение, о котором я должен знать?

1 ответ

Это дает вам ошибку, потому что вы регистрируете контракт условно после того, как действие находится в своем жизненном цикле.

Гид говорит :

Вы всегда должны вызывать в одном и том же порядке для каждого создания вашего фрагмента или действия, чтобы гарантировать, что результаты обработки доставляются правильному обратному вызову.

Понятно, что если вы регистрируете что-то после создания действия, и это происходит только при выполнении условия (события щелчка в данном случае), порядок регистрации не может быть обеспечен.

Лучшим решением было бы зарегистрировать контракт до создания действия и просто вызвать когда вам это нужно. Руководство еще раз говорит, что это совершенно безопасно:

безопасно вызывать перед созданием фрагмента или действия, что позволяет использовать его непосредственно при объявлении переменных-членов для возвращаемых экземпляров ActivityResultLauncher.

Итак, в вашем случае Activity будет выглядеть так:

      class TempActivity: AppCompatActivity() {
    private lateinit var binding: ActivityTempBinding
    
    // registering the contract here
    private val a = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        //SomeCode
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityTempBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.tempBtn.setOnClickListener {
            // launching the registered contract
            a.launch(
                //SomeIntent
            )
        }
    }
}

Дальнейшее объяснение:

Это удобный метод, который внутренне вызывает реестр метод с автоматически созданным ключом. Ключ получен из внутреннего который извлекается и увеличивается каждый раз, когда вы звоните . Поскольку этот ключ используется для поиска обратного вызова, который будет обрабатывать результат, каждый вызов функции должны быть в одном и том же порядке, иначе может случиться так, что вы однажды вызовете его в порядке A (ключ = 0 ), B (ключ = 1 ), а затем вы назовете его B (ключ = 0 ), A (ключ = 1 ). ), или даже не вызывать метод register для одного из контрактов (именно так и происходит, когда вы регистрируетесь в ).

В вашем конкретном случае, если действие воссоздается, пока вы ожидаете возврата запущенного контракта (например, происходит изменение конфигурации или система просто убивает приложение), обратный вызов будет удален из реестра (ключ остается там, хотя ), что означает, что он не будет вызываться с результатами.

Итак, подведем итог: вы можете ( должны ) безопасно зарегистрировать любой контракт в качестве поля участника в своей деятельности или в , и вы никогда не должны регистрировать контракт на лету (то есть условно). Регистрация контракта ничего особенного не даст, настоящая сделка происходит, когда вы его запускаете .