обмен данными между фрагментами через viewmodels

#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. blog.mindorks.com/…

Ответ №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)
           }
       }
    }