我目前在异步图像加载方面遇到一些麻烦,以填充“无限”列表视图(从URL加载数据并存储在自定义适配器中)。我找到了ImageView的this扩展方法,它基本上是koush/UrlImageViewHelper的端口,但原始版本已经更新了很多,现在端口没有更新为9个飞蛾...当我填充时在我的自定义适配器中的ImageView,一切似乎工作正常和快速(我从相当快的服务器下载小图像),但在大约200个图像(每个15-20 kb大小)后,下载停止。我认为问题出在图像缓存中,但即使使用扩展中提供的“清理”方法,也没有任何变化。有谁知道如何解决这个问题,或者有更好的解决方案来完成这项任务?我试图创建自己的“队列”,但它有另一种问题 - 当滚动列表视图时,任何新的ImageView已经有源图像,更改为正确的,但快速滚动这看起来非常糟糕。 这是我的代码:
public override View GetView(int position, View convertView, ViewGroup parent)
{
//Populating the adapter with new items
if (position >= this._items.Count - 1)
ThreadPool.QueueUserWorkItem(o => this.LoadPage());
var item = this._items[position];
View view = convertView;
if (view == null)
view = this._context.LayoutInflater.Inflate(Resource.Layout.CustomRowView, null);
var imgUrl = string.Format(@"http://myserver.com/?action={0}&url={1}", "get.thumbnail", item.Image.Url);
//Here is the image loading row
view.FindViewById<ImageView>(Resource.Id.imageView1).SetUrlDrawable(imgUrl);
view.FindViewById<TextView>(Resource.Id.txtTitle).Text = item.Title;
view.FindViewById<TextView>(Resource.Id.txtYear).Text = item.Information.Year;
view.FindViewById<TextView>(Resource.Id.txtGenre).Text = item.Information.Genre;
view.FindViewById<TextView>(Resource.Id.txtGrade).Text = item.Rating.Grade;
view.FindViewById<TextView>(Resource.Id.txtVotes).Text = string.Format("( {0} )", item.Rating.Votes);
return view;
}
public void LoadPage()
{
OnUpdateAnimeListStart(); //Event to display loading message
try
{
this._items.FillListFromUrl(string.Format("http://myserver.com/page/{0}/", this._page));
}
catch(Exception ex)
{
_context.RunOnUiThread(() =>
{
new AlertDialog.Builder(_context)
.SetPositiveButton("Ok", (sender, args) =>
{
Intent blankIntent = new Intent();
blankIntent.SetFlags(ActivityFlags.ClearTop);
int intPID = Android.OS.Process.MyPid();
Android.OS.Process.KillProcess(intPID);
})
.SetMessage(ex.Message)
.SetTitle("Error!")
.Show();
});
}
this._page++;
_context.RunOnUiThread(() =>
{
_context.FindViewById<ListView>(Resource.Id.listView).InvalidateViews();
});
OnUpdateAnimeListEnd(); //Event to hide loading message
}
public class ImageDownloader
{
private List<ImageView> _queueImageViews;
private List<string> _queueImageUrls;
private Activity _context;
public ImageDownloader(Activity context)
{
this._context = context;
this._queueImageViews = new List<ImageView>();
this._queueImageUrls = new List<string>();
}
public void DownloadImage(ImageView imgView, string url)
{
this._queueImageViews.Add(imgView);
this._queueImageUrls.Add(url);
if (this._queueImageViews.Count == 1)
this._startJob();
}
private void _startJob()
{
WebClient web = new WebClient();
web.DownloadDataCompleted += new DownloadDataCompletedEventHandler(web_DownloadDataCompleted);
web.DownloadDataAsync(new Uri(this._queueImageUrls[0]));
}
private void _removeFromeQueue(int index = 0)
{
this._queueImageUrls.Remove(this._queueImageUrls[index]);
this._queueImageViews.Remove(this._queueImageViews[index]);
}
void web_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
ImageView v = this._queueImageViews[0];
this._context.RunOnUiThread(() =>
{
Bitmap bm = BitmapFactory.DecodeByteArray(e.Result, 0, e.Result.Length);
v.SetImageBitmap(bm);
});
this._removeFromeQueue();
if (this._queueImageViews.Count > 0)
this._startJob();
}
}
提前谢谢。
答案 0 :(得分:1)
解决了我的问题,感谢UrlImageViewHelper端口的更多调试。 正如我所假设的,问题在于缓存。背后的逻辑是将缓存的项目限制为特定的数字(我不知道为什么,但它是硬编码的),如果达到限制,则需要从缓存中删除前几个项目。这很好,但实现仍然有一些错误。现在,而不是调试更多,并修复实现,我将限制增加到5000(最初设置为100),但这只是解决此问题的临时方法。将来我可能会修复代码,因此它会删除缓存集合中的第一个项目。所以这就是:
SoftReferenceHashTable<TKey, TValue>
class 修正了这一行:
LRUCache<TKey, TValue> cache = new LRUCache<TKey, TValue>(100);
对此:
LRUCache<TKey, TValue> cache = new LRUCache<TKey, TValue>(5000);
此外,感谢 @ Y2i 的评论,我发现在UrlImageViewHelper
课程中,SetUrlDrawable
方法无需关闭互联网连接即可实现下载。可能这不是一个问题,但我更愿意解决这个问题。所以我改变了代码的这一部分:
var client = new System.Net.WebClient();
var data = client.DownloadData(url);
System.IO.File.WriteAllBytes(filename, data);
return LoadDrawableFromFile(context, filename);
对此:
using (var client = new System.Net.WebClient())
{
var data = client.DownloadData(url);
System.IO.File.WriteAllBytes(filename, data);
return LoadDrawableFromFile(context, filename);
}
答案 1 :(得分:0)
我有一个类似的问题,这就是我想出的答案。单片机版本的koush / UrlImageViewHelper也给我带来了麻烦。所以我拉开它重建我自己的版本。希望有人会觉得这很有用。
http://xandroid4net.blogspot.com/2014/09/xamarinandroid-loading-images-from-web.html