Android,RecyclerView:异步加载导致商品翻倍

时间:2018-11-21 13:22:17

标签: android android-recyclerview

在我的应用中,我有一个RecyclerView,其中(在我的手机上)包含约700个带有乐队名称的歌曲标题。没什么太疯狂的,但是在UI线程上重新加载所有这些会导致一些滞后。我决定在远离UI线程的Asynctask中进行加载。看起来像这样:

 public class PhotoAlbumAdapter : RecyclerView.Adapter
    {
        public List<MP3objectSmall> mp3Obj;
        Context ctx;
        Activity act;
        MediaMetadataRetriever reader;
        DataBase db;
        List<SeekObj> seekObj;
        Typeface tf;
        AudioManager audioManager;


        public PhotoAlbumAdapter(List<MP3objectSmall> mp3Obj, Context ctx, DataBase db, List<SeekObj> seekObj, AudioManager audioManager, Activity act)
        {

            this.mp3Obj = mp3Obj;
            this.ctx = ctx;
            this.db = db;
            this.seekObj = seekObj;
            this.act = act;
            this.audioManager = audioManager;
            reader = new MediaMetadataRetriever();

            tf = Typeface.CreateFromAsset(ctx.Assets, "Baiti.ttf");
        }

        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
        {
            View itemView = LayoutInflater.From(parent.Context).
                        Inflate(Resource.Layout.CardView, parent, false);
            PhotoViewHolder vh = new PhotoViewHolder(itemView, mp3Obj, act, reader, db, seekObj, audioManager, ctx);
            return vh;
        }

        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            PhotoViewHolder vh = holder as PhotoViewHolder;



            SetContent(vh, position);


        }

        private async void SetContent(PhotoViewHolder vh, int position)
        {
            await SetContentAsync(vh, position);
        }

        public override int ItemCount
        {

            get
            {
                if (mp3Obj != null)
                {
                    return mp3Obj.Count();
                }
                else
                    return 0;
            }
        }

        private async Task SetContentAsync(PhotoViewHolder vh, int position)
        {
            string SongName = "";
            string ArtistName = "";

            await Task.Run(() =>
            {
                try
                {
                    reader.SetDataSource(mp3Obj[position].Mp3Uri);
                }
                catch
                {

                }

                SongName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle);
                ArtistName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist);
            });

            ((Activity)ctx).RunOnUiThread(() =>
            {
                vh.SongName.SetTypeface(tf, TypefaceStyle.Normal);
                vh.AristName.SetTypeface(tf, TypefaceStyle.Normal);
                vh.SongName.Text = SongName;
                vh.AristName.Text = ArtistName;
            });
        }
    }

这确实使整体性能提高了很多,但引起了一些奇怪的副作用:

当我快速向下滚动列表然后突然停止播放时,我连续看到同一首歌曲2-3次。这些项目中只有一个是歌曲本身,其他是不同的歌曲,但它们的开头带有错误的歌曲和歌手姓名。

如果我现在略微向上滚动,以至于双倍项就在屏幕之外,然后向后滚动RecyclerView似乎已纠正了自己,而双倍或有时三倍的项就消失了。

此问题仅在我将加载移至异步任务后才会发生。我可能在这里做错了吗?

2 个答案:

答案 0 :(得分:1)

我认为这里的重点是保留viewHolder的引用。

我建议您尝试这样的方法:

public class PhotoViewHolder extends RecyclerView.ViewHolder {
    private TextView tvSongName;

    public PhotoViewHolder(View v) {
        super(v);
        //initialize here views; ie
        //this.tvSongName = v.findViewById(R.id.tvSongName);
    }

    public void initializeAsync(int position) {
        Handler mHandler = new Handler();
        new Thread(new Runnable() {

            String songName, otherStuff;

          @Override
          public void run () {
            // here we are async.

            // Retrieve here your song informations, ie:
            //object myRetrievedObject = getSongInfoBasedOnPositionSomeHow(); 
            //songName = myRetrievedObject.retrievedSongName;
            //otherStuff = myRetrievedObject.retrievedOtherStuffs;

            mHandler.post(new Runnable() {
             @Override
             public void run () {
               // make operation on UI
                tvSongName.setText(songName);
                //...
                //...
             }
            });
          }
        }).start();
    }
}

并这样称呼:

    public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        PhotoViewHolder vh = holder as PhotoViewHolder;
        vh.initializeAsync(position);
    }

请考虑我是在没有编译器的情况下写的,所以它可能并不完美,无论如何请让我知道。

希望这会有所帮助!

答案 1 :(得分:1)

我认为arraylist会被填充两次。因此,在再次在活动类中再次加载arraylist之前,请使用yourarraylistname.clear();。清除阵列列表,然后在下一次加载数据。因此,每当您再次填充阵列列表时,它将首先被清除,然后再次加载数据。