Поделиться ViewModel между фрагментами, которые находятся в разных действиях

У меня есть ViewModel с именем SharedViewModel:

public class SharedViewModel<T> extends ViewModel {

    private final MutableLiveData<T> selected = new MutableLiveData<>();


    public void select(T item) {
        selected.setValue(item);
    }

    public LiveData<T> getSelected() {
        return selected;
    }
}

Я реализую его на основе примера SharedViewModel на справочной странице Google View View:

https://developer.android.com/topic/libraries/architecture/viewmodel.html

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

У меня есть два фрагмента, называемые ListFragment а также DetailFragment,

До сих пор я использовал эти два фрагмента внутри MasterActivity, И все работало хорошо.

Я получил ViewModel в ListFragmentвыбрал значение для использования DetailFragment,

mStepSelectorViewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

Тем не менее, теперь мне нужно, что в некоторых случаях ListFragment (макет для другой конфигурации устройства), чтобы добавить к другой деятельности, называемой DetailActivity, Есть ли способ сделать это аналогично приведенному выше примеру?

4 ответа

Немного поздно, но вы можете сделать это с помощью общего ViewModelStore, Фрагменты и мероприятия по реализации ViewModelStoreOwner интерфейс. В этих случаях фрагменты имеют хранилище для каждого экземпляра, а действия сохраняют его в статическом члене (я полагаю, что он может выдержать изменения конфигурации).

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

class MyApp: Application(), ViewModelStoreOwner {
    private val appViewModelStore: ViewModelStore by lazy {
        ViewModelStore()
    }

    override fun getViewModelStore(): ViewModelStore {
        return appViewModelStore
    }
}

Затем в тех случаях, когда вы знаете, что вам нужно разделить ViewModels между границами действий, вы делаете что-то вроде этого.

val viewModel = ViewModelProvider(myApp, viewModelFactory).get(CustomViewModel::class.java)

Так что теперь он будет использовать магазин, определенный в вашем приложении. Таким образом, вы можете поделиться ViewModels.

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

Ну, я для этого создал библиотеку под названием Vita, можно поделитьсяViewModels между активностями и даже фрагментами с разной активностью хоста:

val myViewModel = vita.with(VitaOwner.Multiple(this)).getViewModel<MyViewModel>()

Созданный ViewModel таким образом остаться в живых до последнего LifeCycleOwner уничтожен.

Также вы можете создать ViewModels с областью применения:

val myViewModel = vita.with(VitaOwner.None).getViewModel<MyViewModel>()

И этот тип ViewModel будет очищено, когда пользователь закроет приложение

Попробуйте и дайте мне знать свой отзыв:https://github.com/FarshadTahmasbi/Vita

Вы можете использовать фабрику для создания viewmodel, и этот фактор вернет один объект модели представления. Как:

class ViewModelFactory() : ViewModelProvider.Factory {

override fun create(modelClass: Class): T {
    if (modelClass.isAssignableFrom(UserProfileViewModel::class.java)) {
    val key = "UserProfileViewModel"
    if(hashMapViewModel.containsKey(key)){
        return getViewModel(key) as T
    } else {
        addViewModel(key, UserProfileViewModel())
        return getViewModel(key) as T
    }
    }
    throw IllegalArgumentException("Unknown ViewModel class")
}

companion object {
    val hashMapViewModel = HashMap<String, ViewModel>()
    fun addViewModel(key: String, viewModel: ViewModel){
        hashMapViewModel.put(key, viewModel)
    }
    fun getViewModel(key: String): ViewModel? {
        return hashMapViewModel[key]
    }
}
}

В деятельности:

viewModelFactory = Injection.provideViewModelFactory(this)

// Initialize Product View Model
userViewModel = ViewModelProviders.of(this, viewModelFactory).get(
UserProfileViewModel::class.java)`

Это обеспечит только один объект UserProfileViewModel, который вы можете разделить между действиями.

Если вам нужна ViewModel, которая используется всеми вашими действиями (в отличие от некоторых), то почему бы не сохранить то, что вы хотите, в этом ViewModel, хранящемся внутри вашего класса Application?

Тенденция, представленная на последнем вводе / выводе Google, похоже, заключается в том, чтобы отказаться от концепции "Деятельности" в пользу приложений с одним действием, которые содержат много фрагментов. ViewModels - это способ удалить большое количество интерфейсов, которые ранее должен был реализовывать интерфейс. Таким образом, этот подход больше не ведет к гигантской и неосуществимой деятельности.

Я думаю, что мы все еще путаемся с платформой MVVM на Android. Что касается другой деятельности, не запутайтесь, потому что она обязательно должна быть такой же, почему?

Это имеет смысл, если он имеет ту же логику (даже если логика все еще может быть абстрактной в других полезных классах), или если представление в XML почти идентично.

Давайте рассмотрим небольшой пример:

Я создаю ViewModel с именем vmA, и действие с именем A, и мне нужны данные пользователя, я пойду, чтобы вставить репозиторий в vmA пользователя.

Теперь мне нужно другое действие, которое должно читать пользовательские данные, я создаю другую ViewModel с именем vmB, и в ней я буду вызывать хранилище пользователей. Как описано, хранилище всегда одинаково.

Другой предложенный способ - создать N экземпляров той же модели ViewModel с реализацией Factory.

Вот ссылка

Надеюсь, это поможет вам. O(∩_∩)O~

К тому же:

1) вдохновение для кода пришло от smart pointer in c++,

2) Это будет автоматически очищено, когда никакие действия или фрагменты не ссылаются ShareViewModel, ShareViewModel # onShareCleared() функция будет вызываться одновременно! Вам не нужно уничтожать их вручную!

3) Если вы используете dagger2, чтобы ввести ViewModelFactory для обмена моделью представления
между двумя видами деятельности (может быть, три), вот пример