#android #android-jetpack #android-viewmodel
#Android #android-jetpack #android-viewmodel
Вопрос:
Согласно разделу «Обмен данными между фрагментами» на https://developer.android.com/topic/libraries/architecture/viewmodel нам сказали, что создание ViewModel в области действия и совместное использование его среди фрагментов — это правильный путь.
Это фрагмент, который задает значение в ViewModel
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
Это фрагмент сведений, который использует набор свойств
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
Это ViewModel
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
Мой вопрос прост. Предполагая, что MasterFragment устанавливает значение в ViewModel при нажатии кнопки, как мы восстановим это значение при доступе к нему ПОСЛЕ ТОГО, КАК СИСТЕМА ЗАВЕРШИТ РАБОТУ НАШЕГО ПРИЛОЖЕНИЯ И ПЕРЕЗАПУСТИТ ЕГО?.
Наш DetailFragment не будет видеть значение, поскольку мы устанавливали его при нажатии кнопки в главном фрагменте. Чтобы лучше понять вопрос, рассмотрим, что у нас есть фрагменты A, B, C и D, и они совместно используют ViewModel, в котором совместно вычисляются фрагменты значений A, B и C и помещают их в ViewModel для доступа к фрагменту D.
Теперь, когда система завершает работу и воссоздает наше приложение, во фрагменте D это значение будет недоступно.
onSaveInstance также не сможет сильно помочь, не прибегая к грязному коду. Для простых ситуаций — да, но, как в той, в которой фрагменты B и C вместе создают значение, в этой ситуации onSaveInstance было бы проблематичным.
onSaveInstance должен был быть внутри ViewModel, но, увы, я не думаю, что это так. Есть идеи?
Комментарии:
Ответ №1:
Объекты ViewModel ограничены жизненным циклом, передаваемым ViewModelProvider при получении ViewModel. ViewModel остается в памяти до тех пор, пока жизненный цикл, к которому он привязан, не исчезнет навсегда: в случае действия, когда оно завершается, в то время как в случае фрагмента, когда он отсоединяется.
Мой вопрос прост. Предполагая, что MasterFragment установил значение в ViewModel при нажатии кнопки, как бы мы восстановили это значение при доступе к нему ПОСЛЕ ТОГО, КАК СИСТЕМА ЗАВЕРШИЛА РАБОТУ НАШЕГО ПРИЛОЖЕНИЯ И ПЕРЕЗАПУСТИЛА ЕГО?.
Вы не сможете восстановить значение, если приложение отключено пользователем или системой или перезапущено.
Чтобы решить вашу задачу по накоплению данных из действий A, B и C и отобразить их в действии D, даже если приложение отключено или перезапущено, вы можете выбрать любой 1 метод из следующих:
1. SharedPreference
2. Room локальной базы данных или SQLite
3. Сохраняйте данные в файле
Я рекомендую вам использовать SharedPreference для небольших данных и Room для больших и сложных данных.
В двух словах, ViewModel хранит данные временно, чтобы пережить изменение ориентации (нет необходимости писать код onSaveInstanceState
и onRestoreInstanceState
) и обмениваться данными между действиями и фрагментами. Данные будут потеряны, если действие будет уничтожено или фрагмент отсоединен.
Ответ №2:
Если вы все еще хотите получить сохраненное значение после сброса приложения или его завершения, вам необходимо сохранить данные в SharedPreferences или внутренней базе данных SQLite и восстановить их после запуска приложения.
Комментарии:
1. «SharedPreferences или внутренняя база данных SQLite» Вам также разрешено сохранять их с помощью других методов. Вам не нужно использовать ни один из этих двух
2. да, существует больше методов, но это основные и лучшие практики
3.
you need to save data to
Причина, по которой я сделал комментарий, заключается в том, что вы использовали слово «нужно». Вам не НУЖНО использовать эти методы.
Ответ №3:
Для тех, кто использует Kotlin, попробуйте следующий подход:
-
Добавьте библиотеки androidx ViewModel и LiveData в свой файл gradle
-
Вызовите свою viewmodel внутри фрагмента следующим образом:
class MainFragment : Fragment() { private lateinit var viewModel: ViewModel override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) // kotlin does not have a getActivity() built in method instead we use activity, which is null-safe activity?.let { viemModel = ViewModelProvider(it).get(SharedViewModel::class.java) } } }