0

我目前在加载异步图像以填充“无限”列表视图(从 url 加载数据并存储在自定义适配器中)时遇到了一些麻烦。我发现这个ImageView 的扩展方法,基本上是koush/UrlImageViewHelper的端口,但是原始版本更新了很多,并且端口现在没有更新 9 个月了...当我在自定义适配器中填充 ImageView 时,一切似乎都运行良好且快速(我正在从相当快的服务器),但在大约 200 张图像(每个 15-20 kb 大小)之后,下载停止。我认为问题出在图像缓存中,但即使使用扩展中提供的“清理”方法,也没有任何改变。有谁知道如何解决这个问题,或者对该任务有更好的解决方案?我试图创建自己的“队列”,但它有另一种问题 - 滚动列表视图时,任何新的 ImageView 已经有源图像,更改为正确的图像,但是快速滚动看起来非常糟糕。这是我的代码:

我的自定义列表适配器中的 GetView

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();
        }
    }

先感谢您。

4

2 回答 2

1

解决了我的问题,这要归功于 UrlImageViewHelper 端口中的更多调试。正如我所假设的,问题出在缓存中。背后的逻辑是将缓存项目限制为特定数量(我不知道为什么,但它是硬编码的),如果达到限制,则需要从缓存中删除前几个项目。这很好,但实现仍然有一些错误。现在,我没有进行更多调试并修复实现,而是将限制增加到 5000(最初设置为 100),但这只是解决此问题的临时方法。将来我可能会修复代码,因此它将删除缓存集合中的第一个项目。所以这里是:

SoftReferenceHashTable<TKey, TValue>班级

修复了这一行: 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);
}
于 2013-08-10T18:03:25.010 回答
0

我有一个类似的问题,这就是我想出的答案。koush/UrlImageViewHelper 的 Monodroid 版本也给我带来了问题。所以我把它拆开重建了我自己的版本。希望有人会发现这很有用。

http://xandroid4net.blogspot.com/2014/09/xamarinandroid-loading-images-from-web.html

于 2014-09-06T03:48:17.073 回答