首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android,RecyclerView:异步加载导致项目翻倍

Android,RecyclerView:异步加载导致项目翻倍
EN

Stack Overflow用户
提问于 2018-11-21 21:22:17
回答 2查看 868关注 0票数 0

在我的应用程序中,我有一个(在我的手机上)包含大约700首歌曲名称和乐队名称的RecyclerView。没有什么太疯狂的,但在UI线程上重新加载所有这些都会导致一些延迟。我决定在一个异步任务中加载,而不是UI线程。它看起来是这样的:

代码语言:javascript
复制
 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似乎已经进行了自我修正,而加倍或有时是三倍的项目消失了。

此问题仅在我将加载移动到异步任务后才会发生。我是不是做错了什么?

EN

回答 2

Stack Overflow用户

发布于 2018-11-21 22:12:29

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

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

代码语言:javascript
复制
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();
    }
}

然后这样叫它:

代码语言:javascript
复制
    public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        PhotoViewHolder vh = holder as PhotoViewHolder;
        vh.initializeAsync(position);
    }

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

希望这能有所帮助!

票数 1
EN

Stack Overflow用户

发布于 2018-11-22 14:39:22

我认为在activity类中再次加载arraylist之前,arraylist正在填充twice.so;要清除arraylist,然后在下一个tym.So中加载数据,每当您再次填充arraylist时,它将首先被清除,然后再次加载数据。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53413002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档