图像被分配给ListView的另一个行项目

我知道async await非常方便在设置适配器之前为ListView / GridView准备数据。 例如:

// in Activity.cs async void OnCreate(Bundle SavedInstanceState) { SetContentView(...); ListView listView = FindViewById(...); AdapterData data = await Task.Run(() => GetDataFromWorkerThread); listView.SetAdapter(data); } 

但我需要的是:

 // in ListViewAdapter.cs public override View GetView (int position, View convertView, ViewGroup parent) { if(convertView == null) { // create new view } ImageView imgView = convertView.FindViewById(Resouce.Id.img_view_id); ResizeImageAsync(imgView, imgResId); return convertView; // convertView is returned before ImageView is assigned with resized image } private async void ResizeImageAsync(ImageView imageView, int imgResId) { Bitmap bmp = await Task.Run(() => ResizeImage(imgResId, 50, 50)); imageView.SetImageBitmap(bmp); } 

因此,有时在GetView()完成之前返回ResizeImageAsync() convertView 。 问题是image01应该在第一行中分配ImageView现在改为分配给第二行或第三行的ImageView 。 谁知道如何解决这个问题?

问题不在于返回视图,而是它已经离开屏幕并被重用。 然后你启动另一个异步方法并最后完成胜利。 那说你必须取消第一个在同一个视图上启动另一个。 一种解决方案是使用您存储在View.Tag中的CancellationTokenSource。 这为您提供了一种取消以前未完成的异步方法的方法。

这是一个未经过实际测试的语法错误代码。注意,将.net对象存储到View.Tag中需要一个包装器。 另请注意,此代码可能不完美,但应说明要执行的操作。

 public override View GetView(int position, View convertView, ViewGroup parent) { CancellationTokenSource cts; if (convertView == null) { // create new view } else { if (convertView.Tag != null) { var wraper = convertView.Tag.JavaCast>(); if (wraper != null) wraper.Data.Cancel(); } } ImageView imgView = convertView.FindViewById(Resource.Id.img_view_id); cts = new CancellationTokenSource(); ResizeImageAsync(imgView, imgResId, cts.Token); convertView.Tag = new Wrapper { Data = cts }; return convertView; // convertView is returned before ImageView is assigned with resized image } private async Task ResizeImageAsync(ImageView imageView, int imgResId, CancellationToken ct) { Bitmap bmp = await Task.Run(() => ResizeImage(imgResId, 50, 50), ct); if (!ct.IsCancellationRequested) { imageView.SetImageBitmap(bmp); } } public class Wrapper: Java.Lang.Object { public T Data; }