在我的应用中,我有一个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
似乎已纠正了自己,而双倍或有时三倍的项就消失了。
此问题仅在我将加载移至异步任务后才会发生。我可能在这里做错了吗?
答案 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();。清除阵列列表,然后在下一次加载数据。因此,每当您再次填充阵列列表时,它将首先被清除,然后再次加载数据。