J'ai trouvé que les données LiveData renvoyées par Dao appellent leur observateur chaque fois que la ligne est mise à jour dans la base de données, même si la valeur LiveData n'est évidemment pas modifiée.
Prenons une situation semblable à l'exemple suivant:
Exemple d'entité
@Entity
public class User {
public long id;
public String name;
// example for other variables
public Date lastActiveDateTime;
}
Exemple Dao
@Dao
public interface UserDao {
// I am only interested in the user name
@Query("SELECT name From User")
LiveData<List<String>> getAllNamesOfUser();
@Update(onConflict = OnConflictStrategy.REPLACE)
void updateUser(User user);
}
Quelque part dans le fil de fond
UserDao userDao = //.... getting the dao
User user = // obtain from dao....
user.lastActiveDateTime = new Date(); // no change to user.name
userDao.updateUser(user);
Quelque part dans l'interface utilisateur
// omitted ViewModel for simplicity
userDao.getAllNamesOfUser().observe(this, new Observer<List<String>> {
@Override
public void onChanged(@Nullable List<String> userNames) {
// this will be called whenever the background thread called updateUser.
// If user.name is not changed, it will be called with userNames
// with the same value again and again when lastActiveDateTime changed.
}
});
Dans cet exemple, l'interface utilisateur n'est intéressée que par le nom d'utilisateur. Par conséquent, la requête pour LiveData inclut uniquement le champ de nom. Cependant, observer.onChanged sera toujours appelé sur Dao Update même si d’autres champs sont mis à jour . )
Est-ce le comportement conçu de Dao LiveData in Room? Y a-t-il une chance que je puisse contourner ce problème afin que l'observateur ne soit appelé que lorsque le champ sélectionné est mis à jour?
Edit: J'ai changé pour utiliser la requête suivante pour mettre à jour la valeur lastActiveDateTime comme KuLdip PaTel dans le commentaire suggèrent. L'observateur de LiveData du nom d'utilisateur est toujours appelé.
@Query("UPDATE User set lastActiveDateTime = :lastActiveDateTime where id = :id")
void updateLastActiveDateTime(Date lastActiveDateTime, int id);
Cette situation est connue sous le nom de notification faussement positive de l'observateur .Veuillez vérifier le point 7 mentionné dans link pour éviter ce problème.
L'exemple ci-dessous est écrit en kotlin mais vous pouvez utiliser sa version Java pour le faire fonctionner.
fun <T> LiveData<T>.getDistinct(): LiveData<T> {
val distinctLiveData = MediatorLiveData<T>()
distinctLiveData.addSource(this, object : Observer<T> {
private var initialized = false
private var lastObj: T? = null
override fun onChanged(obj: T?) {
if (!initialized) {
initialized = true
lastObj = obj
distinctLiveData.postValue(lastObj)
} else if ((obj == null && lastObj != null)
|| obj != lastObj) {
lastObj = obj
distinctLiveData.postValue(lastObj)
}
}
})
return distinctLiveData
}
Actuellement, il n’existe aucun moyen d’arrêter de déclencher Observer.onChanged, raison pour laquelle j'estime que LiveData sera inutile pour la plupart des requêtes utilisant des jointures . Comme @Pinakin, il existe un MediatorLiveData, mais il ne s'agit les données sont toujours chargées à chaque changement. Imaginez qu'il vous reste 3 jointures dans 1 requête pour laquelle vous n'avez besoin que d'un champ ou de deux de ces jointures. Si vous implémentez PagedList chaque fois qu'un enregistrement de ces 4 tables (principales + 3 tables jointes) est mis à jour, la requête sera appelée à nouveau .C'est correct pour certaines tables avec une petite quantité de données, mais corrigez-moi si Je me trompe, ce serait mauvais si les tables étaient plus grandes ..__ Il serait préférable de pouvoir mettre à jour la requête de manière à ce que la table principale soit mise à jour ou, idéalement, à avoir un moyen de rafraîchir uniquement si les champs de cette requête sont mis à jour dans la base de données.