it-swarm.com.ru

Поделиться 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. Есть ли способ сделать это аналогично приведенному выше примеру? 

12
alexpfx

Немного поздно, но вы можете сделать это с помощью общей 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 живут в экземпляре вашего приложения, они не будут уничтожены, когда фрагмент/действие, которое их использует, будет уничтожено. Поэтому вам придется связать их с жизненным циклом последнего фрагмента/действия, которое будет их использовать, или уничтожить их вручную.

8
mikehc

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

2
Munish Thakur

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

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

1
Marcus Wolschon

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

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

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

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

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

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

0
AlexPad