Как сохранить некоторые данные в элементе адаптера переработчика, чтобы отменить запросы в полете, когда представление перерабатывается? - PullRequest
0 голосов
/ 04 июля 2018

У меня есть адаптер для утилизации, который загружает контент из сети при прокрутке (включая эскизы и некоторые другие данные).

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

Я попытался написать приведенный ниже код, чтобы сделать это:

class SomeRecyclerAdapter(private val dataset: MutableList<SomeData>)
    : RecyclerView.Adapter<SongsRecylerAdapter.ViewHolder>() {

    // ... irrelevant fields here

    var requestInFlight: Job? = null
    var requestInFlight2: Job? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val someListItem = LayoutInflater.from(parent.context)
                .inflate(R.layout.list_item_foo, parent, false)

        return ViewHolder(someListItem)
    }

    override fun getItemCount() = dataset.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val someData = dataset[position]
        holder.someView.text = someData.toString()
        holder.thumbnailView.imageResource = R.drawable.default_thumbnail

        // Cancel any requests currently in flight, to prevent janky stuff on long scrolls
        // Otherwise, if scrolling far, it will load all of the data in sequence
        // We don't want to load the stuff in between before loading the stuff where we are at
        requestInFlight?.cancel()
        requestInFlight2?.cancel()

        requestInFlight = async(UI) {
            var someDataFromServer = listOf<Bar>()

            async(CommonPool) {
                someDataFromServer = someSuspendMethod()
            }.await()

            someData.thumbnailUri = someDataFromServer.thumbnailUri

            GlideApp.with(holder.thumbnailView.context)
                    .load(dataset[position].thumbnailUri)
                    .placeholder(R.drawable.default_thumbnail)
                    .into(holder.thumbnailView)
        }
    }

    // Viewholder here...

}

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

Любая помощь?

1 Ответ

0 голосов
/ 04 июля 2018

Создайте requestInFlight и requestInFlight2 в полях ViewHolder, поскольку каждое из них имеет собственную загрузку, поскольку теперь вы неправильно перезаписываете задания во время прокрутки.

Затем переместите логику отмены в onViewRecycled:

override fun onViewRecycled(holder: ViewHolder){
    holder.requestInFlight?.cancel()
    holder.requestInFlight2?.cancel()
}

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

...