web-dev-qa-db-ja.com

PagedListAdapter.submitList()既存のアイテムを更新するときに奇妙な動作

このトピックの小さな話:アプリは、確認されたときにダイアログでクリックされた行の値を更新するだけです。部屋のデータベースでページ分割シナリオを使用します。

アイテムが追加または削除されると、最新のデータセットがフェッチされ、submitListメソッドに渡されます。その後、すべての変更が表示され、適切に機能します。

問題はそこから始まり、既存のアイテムが更新されると、最新のデータセットが適切にフェッチされてsubmitListに渡されますが、今回は変更されていないようです。

_DIFF_CALLBACK_をデバッグしてareItemsTheSameでアイテムをキャッチしたとき、newHistoryoldHistoryの値は同じです! (どうやって!)

submitListメソッドにバグがある可能性はありますか?

  • 部屋v。:2.1.0-alpha02
  • ページングv。:2.1.0-beta01

初期化後、observeはルームからリストをフェッチしてmHistoryAdapter.submitList(it)に渡します。次に、アイテムを更新すると、再度トリガーされ、param _itに更新された値が表示され、submitListに渡されます。

残念ながら、アダプターは変更されません...

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

すべてのパーツ

型番

_@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
_

アダプタ

_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
            }
        }
    }
}
_

断片

_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)
        })
    }
}
_
12
blackkara

質問には、より詳細な回答を提供するのに役立ついくつかの欠けている点があります。

例あなたのRecyclerView.Adapterはどのように見えますか? PagedListAdapterを拡張しますか?

モデルクラスはどのように見えますか? Kotlinデータクラスですか?


答えを提供するために、それらの未知数が私たちが期待するものであると仮定しましょう。

質問を理解した場合、あなたはアイテムをupdatingだけであり、アイテムを削除または追加していないようです。したがって、古いリストと新しいリストのサイズは変更されていないため、DiffUtil.ItemCallbackareItemsTheSameは常にtrueを返します。つまり、アイテムを更新した場合は、そのコンテンツが更新され、リストから削除されていない可能性があります。

そのため、IDが同じであるため、areItemsTheSameはtrueを返します。

アイテムのコンテンツを更新したため、2番目のメソッドareContentsTheSameはfalseを返す可能性が高くなります。

モデルクラスResolvedAddressがKotlinデータクラスの場合、古いリストと新しいリストから更新されたアイテムを比較すると、メソッドareContentsTheSameはfalseを返します。これにより、この時点でアダプターのonBindViewHolderメソッドがトリガーされ、更新されたデータでそのアイテムを再バインドできます。

そのモデルがKotlin data classではない場合は、クラスがcompareToメソッドを実装していることを確認する必要があります。そうでない場合は、オブジェクトのメモリアドレスとオブジェクトの実際の内容を比較しています。その場合、オブジェクトのメモリアドレスは変更されていないため、メソッドareContentsTheSameは常にtrueを返します。

コードがどのように実装されているかについての知識がなければ、より明確な回答を提供することは困難であるため、これらはデバッグのヒントです。

4
Felipe Roriz

私は同様の問題を抱えていましたが、ここの回答で提案されているように、既存のアイテムを直接更新するのではなく、新しいオブジェクトで既存のアイテムを更新することでなんとか修正しました:

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

0
SQLol