Android Kotlin Coroutine на поворот экрана - PullRequest
0 голосов
/ 15 сентября 2018

Я запускаю сопрограмму, которая после указанной задержки отображает значение счетчика на экране.

job = launch(UI) {
    var count= 0
      while (true) {
        textView.text = "${count++}"
        delay(200L)
      }
   }

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

Ответы [ 3 ]

0 голосов
/ 15 сентября 2018

Вы можете сделать это во ViewModel вместо Activity.

0 голосов
/ 16 сентября 2018

Кто-нибудь знает, как возобновить работу при изменении конфигурации (например, поворот экрана).

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

Хотя технически вы можете настроить свое приложение так, чтобы оно не воссоздало активность при ротации, Google настоятельно не рекомендует вам делать это.Приложение будет работать в случае ротации, но затем будет зависать при изменении конфигурации другого типа, например, часового пояса, местоположения и т. Д. Вам просто нужно прикусить пулю и заставить ваше приложение работать в событиях активного отдыха.

Я заставил свои сопрограммы работать через воссоздание активности, полагаясь на Fragment, в котором я установил

retainInstance = true

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

При изменении конфигурации ваш фрагмент будет проходить через следующие события жизненного цикла:

  1. onDestroyView
  2. onCreateView

Itне проходит через onPause / onResume, это происходит только при переключении действий или выходе из приложения.Вы можете запустить сопрограмму в onResume и отменить ее в onPause.

Начиная с недавно выпущенной версии 0.23 kotlinx.coroutines, launch стала функцией расширения: вы должны вызывать ее в контекстенекоторого CoroutineScope, который контролирует жизненный цикл конечного задания.Вы должны привязать его жизненный цикл к фрагменту, поэтому позвольте вашему фрагменту реализовать CoroutineScope.Другое изменение заключается в том, что контекст сопрограммы UI теперь устарел в пользу Dispatchers.Main.

. Вот краткий пример, который демонстрирует все упомянутые мной пункты:

class MyFragment : Fragment, CoroutineScope {
    private var textView: TextView? = null
    private var rootJob = Job()

    override val coroutineContext: CoroutineContext 
        get() = Dispatchers.Main + rootJob

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        retainInstance = true
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        val rootView = inflater.inflate(R.layout.frag_id, container, false)
        this.textView = rootView.findViewById(R.id.textview)
        return rootView
    }

    override fun onDestroyView() {
        this.textView = null
    }

    override fun onResume() {
        this.launch {
            var count = 0
            while (true) {
                textView?.text = "$count"
                count++
                delay(200L)
            }
        }    
    }

    override fun onPause() {
        rootJob.cancel()
        rootJob = Job()
    }
}

Теперь, какиерархия представления будет перестроена, ваша сопрограмма автоматически выберет текущий экземпляр textView.Если тик по таймеру происходит в неудобный момент, когда пользовательский интерфейс перестраивается, сопрограмма просто молча пропустит обновление представления и попытается снова при следующем тике.

0 голосов
/ 15 сентября 2018

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

Ваши варианты:

1) Добавьте configSettings в манифест, чтобы отключить это поведение.

2) Используйте что-то, что может сохраняться после перезапуска активности, например View Model, загрузчик, внедренную шину событий и т. Д.

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

...