0

Je suis actuellement en train de refactoriser le code existant pour utiliser les composants d'architecture Android et de configurer une demande de db et de vol dans un type de structure de référentiel. Ainsi, la couche de présentation/domaine demande au référentiel de faire en sorte que LiveData-Objects l'observe ou lui demande de se synchroniser avec le serveur, après quoi les anciennes entrées db sont supprimées et toutes les actuelles sont récupérées du serveur.La liste LiveData ne se met pas à jour lors de la mise à jour de la base de données

J'ai écrit des tests pour la partie de synchronisation, donc je suis sûr que les objets sont récupérés et insérés dans la base de données correctement. Mais lors de l'écriture d'un test pour observer les entrées de cette table db (et tester si les objets ont été sauvegardés correctement avec tout ce qu'il faut faire avant de les mettre en db) le LiveData> J'observe, ne se déclenche pas. Dans l'extrait suivant, vous pouvez supposer que la méthode synchronizeFormsWithServer (...) fonctionne correctement et effectue des opérations de base de données de manière asynchrone. Il contient des opérations qui suppriment tous les objets-formes de la base de données qui ne sont pas présents dans la liste des formulaires extraits du serveur et insèrent tous les nouveaux. Depuis au début de l'essai, la base de données est vide cela ne devrait pas beaucoup d'importance que

Le test dans lequel l'observateur ne soit pas déclenché:

@Test 
    public void shouldSaveFormsFromServerIntoDb() throws Exception 
    { 
    Lifecycle lifecycle = Mockito.mock(Lifecycle.class); 
    when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED); 
    LifecycleOwner owner = Mockito.mock(LifecycleOwner.class); 
    when(owner.getLifecycle()).thenReturn(lifecycle); 

    final CountDownLatch l = new CountDownLatch(19); 

    formRepository.allForms().observe(owner, formList -> 
    { 
    if (formList != null && formList.isEmpty()) 
     { 
     for (Form form : formList) 
     { 
     testForm(form); 
     l.countDown(); 
     } 
     } 
    }); 

    formRepository.synchronizeFormsWithServer(owner); 
    l.await(2, TimeUnit.MINUTES); 
    assertEquals(0, l.getCount()); 
    } 

Le code FormRepository:

@Override 
    public LiveData<List<Form>> allForms() 
    { 
    return formDatastore.getAllForms(); 
    } 

Le datastore:

@Override 
    public LiveData<List<Form>> getAllForms() 
    { 
    return database.formDao().getAllForms(); 
    } 

Le code formDao (base de données est mis en œuvre comment vous ex Pect à partir de la chambre):

@Query("SELECT * FROM form") 
    LiveData<List<Form>> getAllForms(); 

Il peut très bien être, que je ne comprenais pas quelque chose sur le LiveData-composants, parce que c'est la première fois les utiliser, alors peut-être que je suis quelque chose de fondamentalement mauvais.

Chaque peu d'aide est très appréciée :)

PS: Je suis tombé sur THIS après, qui traite d'un problème similaire, mais depuis que je suis actuellement pas en utilisant DI du tout et il suffit d'utiliser une seule instance de le formrepository (qui n'a qu'une seule instance de formDao associée) Je ne pense pas que ce soit le même problème.

Répondre

1

Ok, donc j'ai trouvé la solution, bien que je ne sais pas, pourquoi il se comporte de cette façon. Rappelez-vous quand j'ai dit "ne vous inquiétez pas de la méthode de synchronisation"? Eh bien ... il se trouve qu'il y avait deux ou trois choses qui ne marchaient pas, ce qui a retardé la solution.

Je pense que l'erreur la plus importante était la méthode pour mettre à jour les objets dans la base de données lorsque la réponse du réseau est venu. j'appelais

@Update 
void update(Form form) 

dans le dao, qui, pour des raisons inconnues doesn » t déclencher LiveData-Observer. Alors je l'ai changé pour

@Insert(onConflict = OnConflictStrategy.REPLACE) 
void insert(Form form); 

Après avoir fait ce que je pouvais obtenir le formulaire-LiveData de mon dépôt aussi facile que

LiveData<List<Form>> liveData = formRepository.allForms(); 

Alors abonnez-vous à comme d'habitude. Le test précédemment échoué ressemble à ceci maintenant:

@Test 
    public void shouldSaveFormsFromServerIntoDb() throws Exception 
    { 
    Lifecycle lifecycle = Mockito.mock(Lifecycle.class); 
    when(lifecycle.getCurrentState()).thenReturn(Lifecycle.State.RESUMED); 
    LifecycleOwner owner = Mockito.mock(LifecycleOwner.class); 
    when(owner.getLifecycle()).thenReturn(lifecycle); 

    final CountDownLatch l = new CountDownLatch(19); 

    final SortedList<Form> sortedForms = new SortedList<Form>(Form.class, new SortedList.Callback<Form>() 
    { 
     @Override 
     public int compare(Form o1, Form o2) 
     { 
     return o1.getUniqueId().compareTo(o2.getUniqueId()); 
     } 


     @Override 
     public void onChanged(int position, int count) 
     { 
     Log.d(LOG_TAG, "onChanged: Form at position " + position + " has changed. Count is " + count); 
     for (int i = 0; i < count; i++) 
     { 
      l.countDown(); 
     } 
     } 


     @Override 
     public boolean areContentsTheSame(Form oldItem, Form newItem) 
     { 
     return (oldItem.getContent() != null && newItem.getContent() != null && oldItem.getContent().equals(newItem.getContent())) || oldItem.getContent() == null && newItem.getContent() == null; 
     } 


     @Override 
     public boolean areItemsTheSame(Form item1, Form item2) 
     { 
     return item1.getUniqueId().equals(item2.getUniqueId()); 
     } 


     @Override 
     public void onInserted(int position, int count) 
     { 

     } 


     @Override 
     public void onRemoved(int position, int count) 
     { 

     } 


     @Override 
     public void onMoved(int fromPosition, int toPosition) 
     { 

     } 
    }); 

    LiveData<List<Form>> ld = formRepository.allForms(); 
    ld.observe(owner, formList -> 
    { 
    if (formList != null && !formList.isEmpty()) 
     { 
     Log.d(LOG_TAG, "shouldSaveFormsFromServerIntoDb: List contains " + sortedForms.size() + " Forms"); 
     sortedForms.addAll(formList); 
     } 
    }); 

    formRepository.synchronizeFormsWithServer(owner); 
    l.await(2, TimeUnit.MINUTES); 
    assertEquals(0, l.getCount()); 
    } 

Je sais que exactement 19 formulaires auront récupéré à partir du serveur, puis toutes les formes obtiendrai changé une fois (la première fois que je charge une liste contenant toutes les formes avec des données réduite , et la deuxième fois que je charge chaque article du serveur en remplaçant l'ancienne valeur dans le DB avec la nouvelle valeur avec plus de données).

Je ne sais pas si cela va vous aider @ joao86 mais peut-être que vous avez un problème similaire. Si oui, s'il vous plaît assurez-vous de commenter ici :)

1

J'ai eu un problème similaire avec le vôtre ->LiveData is not updating its value after first call

Au lieu d'utiliser LiveData utiliser MutableLiveData et passer l'objet MutableLiveData<List<Form>> au dépôt et à faire setValue ou postValue du nouveau contenu de la liste. D'après mon expérience avec ceci, qui n'est pas beaucoup, apparemment l'observateur est connecté à l'objet que vous lui attribuez d'abord, et chaque changement doit être fait à cet objet.

+0

J'hésite à utiliser votre approche car cela signifierait d'encapsuler tous les appels à mon dépôt dans une asynctask ou quelque chose de similaire, lorsque Room autorise explicitement de telles opérations sur le thread principal si LiveData est renvoyé. Après avoir lu tous les commentaires/messages de chat dans votre question je trouve cela très étrange, cette pièce se comporte comme vous le pensez, même si cela semble être le cas S'il n'y a pas vraiment d'autre option, j'accepterai votre réponse fais comme ça. Mais peut-être que quelqu'un peut jeter plus de lumière sur le problème et trouver un moyen de rendre LiveData directement à partir du dao :) –

+0

J'aimerais aussi cela parce qu'il est un peu étrange que cela se comporte de cette façon :) – joao86

+0

mettre à jour l'interface utilisateur lorsqu'un autre service a modifié les valeurs de la base de données? Parce que oui, si vous actualisez uniquement les valeurs lorsque vous appelez la méthode get (...) du référentiel qui ne pose aucun problème, mais si par exemple un ContentProvider insère quelque chose dans la base de données, je ne pense pas que l'interface affichera change jusqu'à ce que le prochain temps soit appelé (...). Parler de votre code de question lié ici –

0

Désolé de ne pas commenter votre message, je n'ai pas encore la réputation nécessaire, mais j'ai rencontré les mêmes problèmes avec LiveData. Plus précisément, lorsque mon observateur LiveData faisait partie d'une LifecycleActivity ou d'une LifecycleFragment, tout s'est bien passé. Mais quand j'ai essayé d'observer mon LiveData à l'intérieur d'un AppCompatActivity comme proposé par le documentation je n'ai eu aucun événement de changements de données.J'ai observé ce comportement sur alpha8 et alpha9

+0

Comme je l'ai dit dans ma réponse acceptée, il s'agissait d'une mise à jour dans le dao (je pense). Mais je garderai votre réponse à l'esprit quand j'essaie d'observer le LiveData avec un LifeCycleOwner réel lié par un AppCompatActivity. –