PagedListAdapter.submitList () странное поведение при обновлении существующих элементов - PullRequest
0 голосов
/ 21 ноября 2018

Небольшая история в этой теме: приложение просто обновляет значения строки клика в диалоге после подтверждения.Использует сценарий разбиения на страницы в базе данных комнаты.

Когда элемент добавляется или удаляется, последний набор данных выбирается и передается в метод submitList, тогда все изменения видны и хорошо работают.

Проблема начинается там, если существующий элемент обновлен, снова последний набор данных правильно извлекается и передается submitList, но изменения этого времени не кажутся.

Когда я отлаживаю DIFF_CALLBACK и поймаю свой элемент в areItemsTheSame,значения newHistory и oldHistory одинаковы!(Как!)

В методе submitList может быть какая-либо ошибка?

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

После инициализации observe получает список из комнаты и передает mHistoryAdapter.submitList(it).Затем, если я обновляю элемент, наблюдение снова срабатывает (и я вижу обновленное значение в параметре 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)
        })
    }
}

Ответы [ 3 ]

0 голосов
/ 04 февраля 2019

У меня была похожая проблема, но мне удалось ее исправить, обновив существующий элемент новым объектом, а не напрямую обновляя существующий элемент, как предлагается в следующем ответе:

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

0 голосов
/ 06 июня 2019

Объект в наборе данных адаптера обновляется только тогда, когда метод areItemsTheSame или areContentsTheSame возвращает false.

Ваш метод areContentsTheSame должен заботиться обо всех случаях, когда переменные в объекте могут обновляться во время выполнения идолжен вернуть false, если какая-либо переменная изменится, чтобы отразить в наборе данных адаптера, как показано ниже:

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

            // add this if you expect requestedLat to get updated 
            && oldHistory.requestedLat == newHistory.requestedLat

            // add this if you expect requestedLon to get updated 
            && oldHistory.requestedLon == newHistory.requestedLon

            // add this if you expect requestedAddress to get updated 
            && oldHistory.requestedAddress == newHistory.requestedAddress

            // add this if you expect lat to get updated 
            && oldHistory.lat == newHistory.lat


        }
0 голосов
/ 23 ноября 2018

В вопросе отсутствует пара вещей, которые могли бы помочь дать более подробный ответ.

Пример.Как выглядит RecyclerView.Adapter?Это расширяет PagedListAdapter?

Как выглядит класс вашей модели?Это класс данных Kotlin?


Чтобы дать ответ, давайте предположим, что эти неизвестные - это то, что мы ожидаем.

Если я понимаю вопрос, кажется, что вы 'просто updating элемент, а не удаление или добавление элементов.Поэтому DiffUtil.ItemCallback areItemsTheSame всегда будет возвращать true, поскольку старый список и новый список не были изменены с точки зрения их размера.Это означает, что если вы обновили элемент, вы, вероятно, обновили его содержимое и не удалили его из списка.

Следовательно, areItemsTheSame вернет true, потому что их идентификаторы все те же.

Скорее всего, второй метод, areContentsTheSame вернет false, поскольку вы обновили содержимое элемента.

Если класс вашей модели, ResolvedAddress, является классом данных Kotlin, тометод areContentsTheSame должен возвращать значение false при сравнении элемента, который был обновлен из старого списка и нового списка.Это должно вызвать метод onBindViewHolder в вашем адаптере в этот момент, чтобы вы связали этот элемент с обновленными данными.

Если эта модель не является Kotlin data class, то вы должны убедиться, что класс реализуетcompareTo метод.Если нет, вы сравниваете адрес памяти объекта с фактическим содержимым объекта.В этом случае метод areContentsTheSame всегда будет возвращать значение true, поскольку адрес памяти объекта не изменился.

Это некоторые советы по отладке, так как трудно дать более четкий ответ без дополнительных знаний окак код был реализован.

...