Кто-нибудь знает, как возобновить работу при изменении конфигурации (например, поворот экрана).
Ваша работа никогда не прекращалась, но вы продолжаете удерживать и обновлять TextView
, который больше не отображается на экране.После изменения конфигурации ваша деятельность и вся ее иерархия представлений были очищены.
Хотя технически вы можете настроить свое приложение так, чтобы оно не воссоздало активность при ротации, Google настоятельно не рекомендует вам делать это.Приложение будет работать в случае ротации, но затем будет зависать при изменении конфигурации другого типа, например, часового пояса, местоположения и т. Д. Вам просто нужно прикусить пулю и заставить ваше приложение работать в событиях активного отдыха.
Я заставил свои сопрограммы работать через воссоздание активности, полагаясь на Fragment
, в котором я установил
retainInstance = true
Это означает, что ваш экземпляр фрагмента переживает смерть своей родительской активности и, когда новая активность заменяет ееAndroid внедряет ваш фрагмент в него вместо создания нового.Это не предотвращает разрушение иерархии представления, вы должны написать код, который обновляет состояние фрагмента, чтобы отразить эти изменения.Это помогает, потому что позволяет вам сохранить состояние фрагмента, вместо того, чтобы беспокоиться о парселизации.
При изменении конфигурации ваш фрагмент будет проходить через следующие события жизненного цикла:
onDestroyView
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
.Если тик по таймеру происходит в неудобный момент, когда пользовательский интерфейс перестраивается, сопрограмма просто молча пропустит обновление представления и попытается снова при следующем тике.