Share 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 Arch ViewModel:

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

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

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

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

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

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

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

Ответ 1

Немного поздно, но вы можете выполнить это, используя общий 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)

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

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

Ответ 2

вы можете использовать factory, чтобы сделать 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, который вы можете разделить между действиями.

Ответ 3

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

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

Ответ 4

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

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

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

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

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

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

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

Ответ 5

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

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

Давайте возьмем быстрый пример:

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

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

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

Ответ 6

Здесь ссылка

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

К тому же:

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

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

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