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