Shared ViewModel para ajudar na comunicação entre fragmentos e atividade pai
Enquanto o componente Navegação do JetPack parece bastante promissor, cheguei a um lugar em que não conseguia encontrar uma maneira de implementar o que queria.
Vamos dar uma olhada em uma tela de exemplo de aplicativo:
O aplicativo tem uma atividade principal, uma barra de ferramentas superior, uma barra de ferramentas inferior com fab anexado. Existem 2 desafios que estou enfrentando e quero fazê-los da maneira certa.
1. Preciso implementar transações de fragmento para permitir a substituição do fragmento na tela, com base na interação do usuário. Existem três maneiras de pensar e implementar isso:
o retorno de chamada. Tendo uma interfaceonFragmentAction
retorno de chamada em fragmento e ter atividade implementá-lo. Então, basicamente, quando o usuário pressiona um botãoFragmentA
eu posso ligaronFragmentAction
com parâmetros, para que a atividade seja acionada e inicie, por exemplo, uma transação para substituí-la porFragmentB
implementoNavigation
componente do JetPack. Embora eu tenha tentado e pareça bem direto, tive um problema ao não conseguir recuperar o fragmento atual.Use um compartilhadoViewModel
entre fragmento e atividade, atualize-o e observe-o na atividade. Isso seria uma "substituição" dos retornos de chamada2. Desde oFAB
está na atividade pai, quando pressionado, preciso poder interagir com o fragmento visível atual e executar uma ação. Por exemplo, adicione um novo item em uma reciclagem dentro do fragmento. Então, basicamente, uma maneira de se comunicar entre a atividade e o fragmento Existem duas maneiras de pensar em como fazer isso
Navigation
então eu posso usarfindFragmentById
e recupere o fragmento atual e execute um método público para acionar a ação.Usando um 'ViewMode' compartilhado entre fragmento e atividade, atualize-o da atividade e observe-o no fragmento.Portanto, como você pode ver, a maneira recomendada de fazer a navegação seria usar o novo componente da arquitetura 'Navigation', no entanto, no momento, falta uma maneira de recuperar a instância atual do fragmento para que eu não saiba como me comunicar. a atividade e fragmento. Isso pode ser alcançado comshared ViewModel
mas aqui tenho uma peça que falta: entendo que a comunicação entre fragmentos pode ser feita com um ViewModel compartilhado. Eu acho que isso faz sentido quando os fragmentos têm algo em comum para isso, como um cenário Mestre / Detalhe e compartilhar o mesmo modelo de exibição é muito útil.
Mas, então, falando entre atividade eTUDO fragmentos, como poderiaViewModel
ser usado? Cada fragmento precisa de seu próprio ViewModel complexo. Poderia ser umGeneralViewModel
que é instanciado na atividade e em todos os fragmentos, junto com o modelo de exibição de fragmento regular, portanto, tem 2 modelos de exibição em cada fragmento.
Ser capaz de falar entre fragmentos e atividade com um viewmodel tornará desnecessário o achado de fragmento ativo, pois o viewmodel fornecerá o mecanismo necessário e também permitirá o usoNavigation
componente.
Qualquer informação é recebida com prazer.
Depois edite. Aqui está um exemplo de código com base no comentário abaixo. Esta é uma solução para minha pergunta? Isso pode lidar com as alterações entre os fragmentos e a atividade dos pais e está no lado recomendado.
private GlobalViewModel ():ViewModel(){
var eventFromActivity:MutableLiveData<Event>
var eventFromFragment:MutableLiveData<Event>
fun setEventFromActivity(event:Event){
eventFromActivity.value = event
}
fun setEventFromFragment(event:Event){
eventFromFragment.value = event
}
}
Então na minha atividade
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)
}
}
Então em todos os fragmentos tem algo parecido com isto
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)
}
}