web-dev-qa-db-fra.com

PagedListAdapter.submitList () au comportement étrange lors de la mise à jour d'éléments existants

Petite histoire de ce sujet: l'application met à jour les valeurs de la ligne cliquée avec la boîte de dialogue lorsqu'elle est confirmée. Utilise le scénario de pagination dans la base de données de la salle.

Lorsqu'un élément est ajouté ou supprimé, le dernier jeu de données est récupéré et transmis à la méthode submitList, puis toutes les modifications sont visibles et correctement traitées.

Le problème commence ici, si un élément existant est mis à jour, le dernier jeu de données est à nouveau récupéré correctement et transmis à submitList, mais cette fois, les modifications ne semblaient pas.

Lorsque je débogue le DIFF_CALLBACK et attrape mon élément dans areItemsTheSame, les valeurs newHistory et oldHistory sont identiques! (Comment!)

Il pourrait y avoir un bogue dans la méthode submitList

  • Salle v.: 2.1.0-alpha02 
  • Paging v.: 2.1.0-beta01

Après l’initialisation, observe récupère la liste de la pièce et passe à mHistoryAdapter.submitList(it). Ensuite, si je mets à jour un élément, observe est à nouveau déclenché (et je vois la valeur mise à jour dans param it) et passe à submitList

Malheureusement, l'adaptateur ne changera pas ...

    mResolvedAddressViewModel = ViewModelProviders.of(this).get(ResolvedAddressViewModel::class.Java)
    mResolvedAddressViewModel.getAddresses(false).observe(this, Observer {
        mHistoryAdapter.submitList(it)
    })

Toutes les parties

Modèle

@Parcelize
@Entity
data class ResolvedAddress(
    @PrimaryKey var id: String = UUID.randomUUID().toString(),
    var requestedLat: Double = 0.0,
    var requestedLon: Double = 0.0,
    var requestedAddress: String = "",
    var lat: Double,
    var lon: Double,
    var address: String,
    var country: String,
    var countryCode: String,
    var city: String,
    var alias: String? = null,
    var favorite: Boolean = false,
    var provider: String? = null,
    var lastUseDate: Long = 0L) : Parcelable

Adaptateur

class HistoryAdapter(var context: Context)
: PagedListAdapter<ResolvedAddress, HistoryItemHolder>(DIFF_CALLBACK) {

    companion object {
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ResolvedAddress>() {
            override fun areItemsTheSame(
                oldHistory: ResolvedAddress, newHistory: ResolvedAddress): Boolean {
                return oldHistory.id == newHistory.id
            }

            override fun areContentsTheSame(
                oldHistory: ResolvedAddress, newHistory: ResolvedAddress): Boolean {
                return oldHistory == newHistory
            }
        }
    }
}

Fragment

class HistoryFragment : Fragment() {
    private lateinit var mHistoryAdapter: HistoryAdapter
    private lateinit var mResolvedAddressViewModel: ResolvedAddressViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 
        savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_history, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        recyclerViewHistory.setHasFixedSize(true)
        recyclerViewHistory.layoutManager = LinearLayoutManager(activity)
        recyclerViewHistory.itemAnimator = DefaultItemAnimator()

        mHistoryAdapter = HistoryAdapter(context!!)
        recyclerViewHistory.adapter = mHistoryAdapter

        mResolvedAddressViewModel = ViewModelProviders.of(this)
        .get(ResolvedAddressViewModel::class.Java)

        mResolvedAddressViewModel.getAddresses(false).observe(this, Observer {
            mHistoryAdapter.submitList(it)
        })
    }
}
7
blackkara

Il manque quelques éléments dans la question qui pourraient aider à fournir une réponse plus détaillée. 

Ex. À quoi ressemble votre RecyclerView.Adapter? Est-ce que cela étend PagedListAdapter?

A quoi ressemble votre classe modèle? Est-ce une classe de données Kotlin?


Par souci de réponse, supposons que ces inconnues correspondent à nos attentes.

Si je comprends la question, il semble que vous êtes simplement updating un élément et que vous ne supprimez ou n’ajoutez aucun élément . Par conséquent, le areItemsTheSame de DiffUtil.ItemCallback retournera toujours vrai, car l'ancienne liste et la nouvelle liste n'ont pas été modifiées Cela signifie que, si vous avez mis à jour un élément, vous avez probablement mis à jour son contenu et ne l'avez pas supprimé de la liste.

Par conséquent, areItemsTheSame retournera la valeur true, car leurs identifiants sont toujours les mêmes.

Il est plus probable que la deuxième méthode, areContentsTheSame, retourne false puisque vous avez mis à jour le contenu de l'élément.

Si votre classe de modèle, ResolvedAddress, est une classe de données Kotlin, la méthode areContentsTheSame doit renvoyer false lors de la comparaison de l'élément mis à jour à partir de l'ancienne et de la nouvelle liste. Cela devrait déclencher la méthode onBindViewHolder dans votre adaptateur à ce stade pour vous permettre de relier cet élément aux données mises à jour.

Si ce modèle n'est pas un Kotlin data class, vous devez vous assurer que la classe implémente la méthode compareTo. Sinon, vous comparez l'adresse mémoire de l'objet avec le contenu réel de l'objet. Si tel est le cas, la méthode areContentsTheSame retournera toujours la valeur true, l'adresse de mémoire de l'objet n'ayant pas changé.

Voici quelques conseils de débogage, car il est difficile de fournir une réponse plus claire sans plus de connaissances sur la manière dont le code a été implémenté.

4
Felipe Roriz

J'avais un problème similaire, mais j'ai réussi à le résoudre en mettant à jour l'élément existant avec un nouvel objet plutôt qu'en mettant directement à jour l'élément existant, comme suggéré par cette réponse ici:

https://stackoverflow.com/a/54505078/10923311

0
SQLol