Запустить сопрограмму из события щелчка во фрагменте - PullRequest
3 голосов
/ 06 января 2020

Как правильно запустить сопрограмму из события щелчка, определенного во фрагменте? Насколько я понимаю, GlobalScope.launch используется, если вы хотите запустить сопрограмму, которая должна оставаться в памяти в течение всего жизненного цикла приложения. Но так как жизненный цикл фрагмента обычно короче, чем у приложения, GlobalScope.launch, вероятно, не является правильным способом. Я предполагаю, что если бы я использовал GlobalScope.launch, это могло бы помешать фрагменту быть собранным мусором?

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

Ответы [ 2 ]

3 голосов
/ 06 января 2020

Вам необходимо job для обработки отмены сопрограмм для предотвращения утечек:

//inside Fragment
val job = Job()
val uiScope = CoroutineScope(Dispatchers.Main + job)


//late in the button click

button.setOnClickListener{
  uiScope.launch(Dispatchers.IO){
    //asyncOperation
    withContext(Dispatchers.Main){
     //ui operation
   }

  }
}

//later in on destroy:

override fun onDestroy(){
  job.cancel()
  super.onDestroy()
}

Вы также можете использовать расширение LifecycleScope от Google:

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

Редактировать, если вы перезапустите другую операцию. Просто используйте ту же область:

//let's assume you have a second button

button2.setOnClickListener{
  uiScope.launch(Dispatchers.IO){
    //perform second operation
  }
}
1 голос
/ 06 января 2020

GlobalScope.launch используется, если вы хотите запустить сопрограмму, которая должна оставаться в памяти в течение всего жизненного цикла приложения.

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

Я предполагаю, что если бы я использовал GlobalScope.launch, он мог бы сохранить фрагмент из мусора?

Только если сопрограмма сохраняет ссылку на фрагмент или его часть, и только если она может работать в течение длительного времени.

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

Как правильно запустить сопрограмму из события щелчка, определенного во фрагменте?

Проще всего это сделать, следуя официальной документации :

class MyFragment : Fragment, CoroutineScope by MainScope {

    override fun onDestroy() {
        cancel() // extension on CoroutineScope
    }

    ... rest of your fragment code ...
}

. Здесь описывается идиома, которую вам раньше приходилось писать вручную (как видно из другого ответа здесь).

...