В то время как навигационный компонент JetPack выглядит довольно многообещающе, я дошел до того, что не мог найти способ реализовать то, что хотел.
Давайте посмотрим на пример экрана приложения:
В приложении есть одно основное действие: верхняя панель инструментов, нижняя панель инструментов с прикрепленным потрясающим элементом. Есть две проблемы, с которыми я сталкиваюсь, и я хочу решить их правильно.
<сильный>1. Мне нужно реализовать транзакции фрагментов, чтобы разрешить замену фрагмента на экране в зависимости от взаимодействия с пользователем. Есть три способа, которые я могу придумать и реализовать:
- путь обратных вызовов. Наличие обратного вызова интерфейса
onFragmentAction
во фрагменте и реализация его действия. Таким образом, в основном, когда пользователь нажимает кнопку вFragmentA
, я могу вызватьonFragmentAction
с параметрами, чтобы действие запускалось и запускало, например, транзакцию, чтобы заменить ее наFragmentB
- внедрить компонент
Navigation
из JetPack. Хотя я попробовал это и кажется довольно простым, у меня возникла проблема, поскольку я не смог получить текущий фрагмент. - Используйте общий
ViewModel
между фрагментом и действием, обновите его из фрагмента и наблюдайте за ним в действии. Это будет «замена» обратных вызовов
<сильный>2. Поскольку FAB
находится в родительской активности, при нажатии мне нужно иметь возможность взаимодействовать с текущим видимым фрагментом и выполнять действие. Например, добавьте новый элемент в recyclerview внутри фрагмента. Таким образом, в основном способ связи между действием и фрагментом Есть два способа, которыми я могу думать о том, как сделать это
- Если не использовать
Navigation
, я могу использоватьfindFragmentById
и получить текущий фрагмент и запустить общедоступный метод для запуска действия. - Используя общий «ViewMode» между фрагментом и действием, обновите его из действия и наблюдайте за ним во фрагменте.
Итак, как вы можете видеть, рекомендуемым способом навигации будет использование нового архитектурного компонента «Навигация», однако на данный момент ему не хватает способа получить текущий экземпляр фрагмента, поэтому я не знаю, как общаться между деятельность и фрагмент. Этого можно было бы достичь с помощью shared ViewModel
, но здесь у меня есть недостающая часть: я понимаю, что связь между фрагментами может осуществляться с помощью общей ViewModel. Я думаю, что это имеет смысл, когда у фрагментов есть что-то общее для этого, например сценарий Master/Detail, и совместное использование одной и той же модели представления очень полезно.
Но если говорить между действием и ВСЕМИ фрагментами, как можно использовать общий ViewModel
? Для каждого фрагмента нужна своя сложная ViewModel. Может ли это быть GeneralViewModel
, который создается в действии и во всех фрагментах вместе с обычной моделью представления фрагмента, поэтому в каждом фрагменте должно быть 2 модели представления.
Возможность общения между фрагментами и активностью с моделью представления сделает поиск активного фрагмента ненужным, поскольку модель представления предоставит необходимый механизм, а также позволит использовать компонент Navigation
.
Любая информация с радостью принимается.
Позже редактировать. Вот пример кода, основанный на комментарии ниже. Это решение моего вопроса? Может ли это обрабатывать как изменения между фрагментами, так и родительской активностью, и это на рекомендуемой стороне.
private class GlobalViewModel ():ViewModel(){
var eventFromActivity:MutableLiveData<Event>
var eventFromFragment:MutableLiveData<Event>
fun setEventFromActivity(event:Event){
eventFromActivity.value = event
}
fun setEventFromFragment(event:Event){
eventFromFragment.value = event
}
}
Тогда в моей деятельности
class HomeActivity: AppCompatActivity(){
onCreate{
viewModel = ViewModelProviders.of(this, factory)
.get(GlobalViewModel::class.java)
viewModel.eventsFromFragment.observe(){
//based on the Event values, could update toolbar title, could start
// new fragment, could show a dialog or snackbar
....
}
//when need to update the fragment do
viewModel.setEventFromActivity(event)
}
}
Тогда во всех фрагментах есть что-то вроде этого
class FragmentA:Fragment(){
onViewCreated(){
viewModel = ViewModelProviders.of(this, factory)
.get(GlobalViewModel::class.java)
viewModel.eventsFromActivity.observe(){
// based on Event value, trigger a fun from the fragment
....
}
viewModelFragment = ViewModelProviders.of(this, factory)
.get(FragmentAViewModel::class.java)
viewModelFragment.some.observe(){
....
}
//when need to update the activity do
viewModel.setEventFromFragment(event)
}
}
ViewModel
за штуку, если каждыйViewModel
в действии/фрагменте относится к другому классу. Может ли это быть GeneralViewModel, который создается в действии и во всех фрагментах вместе с обычной моделью представления фрагмента, поэтому в каждом фрагменте должно быть 2 модели представления. -- да. Однако это очень длинный вопрос, и поэтому я предполагаю, что да - это не тот ответ, который вы ищете, или, возможно, я что-то упускаю в вопросе. - person CommonsWare   schedule 25.07.2018ViewModel
,LiveData
,Room
,Navigation
и смешивать их наилучшим образом. - person Alin   schedule 25.07.2018GlobalViewModel
,eventsFromActivity()
,FragmentA
,FragmentAViewModel
и т. д. Именно это я имел в виду, когда предположил, что ваши имена являются заполнителями. - person CommonsWare   schedule 26.07.2018GlobalViewModel
, так как он будет использоваться родительской активностью и всеми остальными фрагментами, поэтому он является глобальным.eventsFromActivity
иeventsFromFragment
также могут работать, поскольку единственная цель этой ViewModel - передавать события такого рода. Еще лучше реализовать способ обработкиEvent
только один раз, чтобы избежать повторного запуска при изменении ориентации, и все будет выглядеть хорошо. Я на самом деле попробовал и работает так, как мне нужно, активность может общаться с фрагментом без каких-либо обратных вызовов и интерфейсов. Потрясающий. Спасибо. - person Alin   schedule 26.07.2018