terça-feira, 3 de julho de 2018

Rumo ao Certificado Android: ViewModel

O que é?
ViewModel é uma classe utilizada para manter os dados relacionados com os elementados gráficos, como se fosse um cache, para os mesmos persistirem depois de alguma mudança de configuração, como rotação de tela.

Como usar?
1. Criando uma Classe ViewModel
Crie uma classe que herdará a classe AndroidViewModel e coloque para implementar o construtor:

01. public class MainViewModel extends AndroidViewModel{
   
02.    public MainViewModel(@NonNull Application app){
03.       super(app);
04.    }
05. }


2. Crie o cache
Continuaremos utilizando o exemplo anterior com o Objeto LiveData e o DAO, então criaremos uma Lista de NameEntry que modificamos no tutorial de LiveData (linha 02) e um getter para esta variável (linha 06-09):

01. public class MainViewModel extends AndroidViewModel{
   
02.    private LiveData<List<NameEntry>> names;

03.    public MainViewModel(@NonNull Application app){
04.       super(app);
05.    }

06.    public LiveData<List<NameEntry>> getNames(){
07.       return names;
08.    }
09. }

3. Inicialize o cache
Obtenha o banco de dados e popule a variável cache no construtor (linha 05-06):

01. public class MainViewModel extends AndroidViewModel{
   
02.    private LiveData<List<NameEntry>> names;

03.    public MainViewModel(@NonNull Application app){
04.       super(app);
          
05.       AppDatabase db = AppDatabase.getInstance(
                                  this.getApplication());
06.       names = db.NameDao().getAllNames();
                             
07.    }

08.    public LiveData<List<NameEntry>> getNames(){
09.       return names;
10.    }
11. }

4. Obtendo os dados do ViewModel
Pegando o exemplo do tutorial LiveData, vamos usar a mesma atividade e métodos visto no adicionando Observer. Vamos fazer as seguintes mudanças, agora não vamos mais pegar o dados direto do Banco de Dados, mas do viewModel, portanto, vamos instânciar o ViewModel e pegar os dados de lá (Linhas 03-04):

01. public class ActivityName extends Activity{

02.   private void getAllNames(){
03.     MainViewModel vmodel = ViewModelProviders.of(this)
                                                 .get(MainViewModel.class);
04.     vmodel.getNames().observe(this, new Observer<List<NameEntry>>(){
          
05.        @Override
06.        public void onChange(@Nullable List<NameEntry> namesEntries){
07.           //Recebendo os dados atualizados do LiveData
08.        }

09.     });

10.  }

11.}

Mas e se precisar de um Parâmetro
O caso visto até agora é o caso mais simples, obtendo dados só requisitando, sem parâmetros algum. Mas e se nós precisar de um parâmetro? Por exemplo, para a consulta de Nomes por id? Como fazemos? Bem, para relembrar, vamos pegar a segunda consulta do DAO em questão e colocar o LiveData nele (linha 12):

01. @Dao
02. public interface NameDao{

03.   @Query("SELECT * FROM name ORDER BY priority")
04.   LiveData<List<NameEntry>> loadAllNames();

05.   @Insert
06.   void insertName(NameEntry nameEntry);

07.   @Update(onConflict=OnConflictStrategy.REPLACE)
08.   void updateName(NameEntry nameEntry);

09.   @Delete
10.   void deleteName(NameEntry nameEntry);

11.   @Query("SELECT * FROM name WHERE id=:id")
12.   LiveData<NameEntry> loadNameById(int id);
13. }

1. Criando uma nova ViewModel
Como vamos criar uma nova ViewModel para a consulta modificada. Vamos dar o nome de SingleNameViewModel. Como estaremos gerando os objetos dessa classe através de uma Factory, podemos herdar somente o ViewModel ao invés do AndroidViewModel (Linha 01). Nesta classe um membro privado que representa o dado obtido (Linha 02) e um getter para o mesmo (Linha 06-08). Também iniciaremos o mesmo em um construtor fazendo uma consulta ao banco de dados (Linha 03-05).

01. public class SingleNameViewModel extends ViewModel{
   
02.   private LiveData<NameEntry> name;

03.   public SingleNameViewModel(AppDatabase database, int taskID){
04.      name = database.nameDao().loadNameById(taskID);
05.   }

06.   public LiveData<NameEntry> getName(){
07.      return name;
08.   }
09. }

2. Criando uma Classe ViewModelFactory
Como neste caso precisamos passar um ID para o ViewModel, vamos utilizar uma ViewModelFactory para isso, dado que diversos IDs podem ser usados, cada um independente do outro. Para isso, crie uma nova classe que herdará a classe NewInstaceFactory de ViewModelProvider (Linha 01). Essa classe vai precisar de dois membros: uma instância do banco de dados (Linha 02) e o ID do nome que queremos observar (linha 03). E também criamos um construtor para iniciar os membros (Linha 04-07). Por fim, vamos sobrescrever o método Create para retornar um novo ViewModel que usará os membros inicializados (linha 08-10).

01. public class SingleNameViewModelFactory extends ViewModelProvider.NewInstanceFactory{

02.   private final AppDatabase db;
03.   private final int nameID;

04.   public SingleNameViewModelFactory(AppDatabase database, int nameID){
05.     this.db = database;
06.     this.nameID = nameID;
07.   }

08.   public <T extends ViewModel> T create(Class<T> modelClass){
09.     return (T) new SingleNameViewModel(db, nameID);
10.   }

11. }

3. Usando em uma atividade
Em algum método da atividade que vai usar, precisaremos primeiro instanciar a Factory (Linha 03). Então segue semelhante ao anterior, mas ao invés somente a atividade, passamos também a factory (Linha 04). E de resto é igual anteriormente para pegar os dados e sobrescrevendo o OnChange do Observer (linha 05-09).

01. public class ActivityName extends Activity{
  
02.   private void randomMethod(AppDatabase db, int id){
03.      SingleNameViewModelFactory factory =  new SingleNameViewModelFactory(db,id);
04.      final SingleNameViewModel viewModel = ViewModelProviders.of(this, factory).get(SingleNameViewModel.class);
05.      viewModel.getName().observe(this, new Observer<NameEntry>(){
06.         @Override
07.         public void onChanged(@Nullable NameEntry nameEntry){
           //Atualização do LiveData
08.         }
09.      });
10.   }
11. }

Nenhum comentário:

Postar um comentário