RecyclerView: Async image-loading

前端 未结 7 859
被撕碎了的回忆
被撕碎了的回忆 2020-12-28 15:58

Im using RecyclerView to display a list containing an imageView. To make the UI more fluently, I load 58dp thumbnails saved on sd card into these i

7条回答
  •  抹茶落季
    2020-12-28 16:44

    You should cancel the old request before starting a new one, but regardless of cancelling you can still show the wrong image if both images loaded more or less at the same time on the same container/view holder that has been recycled (happens easily with fast scroll and small images).

    The solution is to:

    1. Store some unique identifier in the View Holder during onBindViewHolder (this happens synchronously so if VH is recycled this will be overwritten)
    2. Then load the image asynchronously (with AsynchTask, RxJava, etc) and pass this unique id in the async call for reference
    3. Finally, in the image loaded method for post-processing (onPostExecute for AsyncTasks), check that the id passed in the async request is the same as the current id present in the View Holder.

    Example loading icons from apps in background with RxJava:

     public void loadIcon(final ImageView appIconView, final ApplicationInfo appInfo, final String uniqueAppID) {
        Single.fromCallable(() -> {
                return appIconView.getContext().getPackageManager().getApplicationIcon(appInfo);
            })
              .subscribeOn(Schedulers.computation())
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe( drawable -> {
                     if (uniqueAppID.equals(mUniqueAppID)) { // Show always the correct app icon
                        appIconView.setImageDrawable(drawable);
                     }
                 }
             );
    }
    

    Here mUniqueAppID is a field of the view holder changed by onBindViewHolder

提交回复
热议问题