使用UICollectionView时,我遇到了一些性能问题,其中单元格正在显示图像(从HD加载)。
我通过在后台加载图片解决了这个问题。
基本上,在我的“GetCell”方法中,我检查图像是否在我的ImageCache中。
我的后台流程片段:
ThreadPool.QueueUserWorkItem (delegate {
ImagesCache.AddImageToCache(""+indexPath.Row,ImageForPosition(indexPath.Row));
InvokeOnMainThread (delegate {
collectionView.ReloadItems(Converter.ToIndexPathArray(indexPath));
});
});
它工作正常,但是如果你快速滚动,它将加载所有这些异步任务,问题是它将按顺序执行请求(FIFO)。因此,当您快速滚动时,将在可见单元格的图像之前加载不可见单元格的图像。
有没有人知道如何优化此流程以获得更好的用户体验? 因为如果我将此扩展到包含来自互联网的图像,问题将更糟(因为下载)。
增加同时线程的最大数量将允许后来添加的线程立即启动但会降低整体性能/下载速度,因此这也不是真正的解决方案。
谢谢, 马特
答案 0 :(得分:0)
我的项目简介:一个thread
下载queue
支持的图片。另外检查目标UI
控件,它没有出列以便重复使用。
长版:
queue
/ Start
实施Stop
。当Start
正在调用时,启动后台线程,在繁忙循环(while true { DoSomething(); }
)中将尝试从队列中出队请求。如果没有出队,请稍微睡一觉。如果出列,请执行它(下载图像)。 Stop
方法应该说线程退出循环:public void Start()
{
if (started) {
return;
}
started = true;
new Thread (new ThreadStart (() => {
while (started) {
var request = GetRequest();
if (request != null) {
request.State = RequestState.Executing;
Download (request);
} else {
Thread.Sleep (QueueSleepTime);
}
}
})).Start ();
}
public void Stop()
{
started = false;
}
queue
中创建一个私有方法来下载具有这种逻辑的图像:检查文件缓存中的图像。如果文件可用,请阅读并返回。如果没有,请下载,保存到文件,返回(调用Action<UIImage> onDownload
)或错误(调用Action<Exception> onError
)。在queue
的忙循环中调用此方法。将其命名为Download
:public Download(Request request)
{
try {
var image = GetImageFromCache(request.Url);
if (image == null) {
image = DownloadImageFromServer(request.Url); // Could be synchronous
}
request.OnDownload(image);
} catch (Exception e) {
request.OnError(e);
}
}
Command
对于包装队列请求非常有用:存储Actions
,当前State
。将其命名为DownloadImageAsync
:public DownloadImageAsync(string imageUrl, Action<UIImage> onDownload, Action<Exception> onError)
{
var request = MakeRequestCommand(imageUrl, onDownload, onError);
queue.Enqueue(request);
}
UITableViewCell
准备展示并请求下载图片时:// Custom UITableViewCell method, which is called in `UITableViewSource`'s `GetCell`
public void PrepareToShow()
{
var imageURLClosure = imageURL;
queue.DownloadImageAsync(imageURL, (UIImage image) => {
if (imageURLClosure == imageURL) {
// Cell was not dequeued. URL from request and from cell are equals.
imageView.Image = image;
} else {
// Do nothing. Cell was dequeued, imageURL was changed.
}
}, (Exception e) => {
// Set default image. Log.
});
}
检查(imageURLClosure == imageURL)非常重要,以避免在快速滚动时在一个UIImageView
中显示多个图像。一个单元可以初始化多个请求,但只应使用最后一个结果。
进一步改进:
Action<byte[]> onDownload
代替Action<UIImage> onDownload
进行跨平台代码兼容; download image
请求的可用性(WillMoveToSuperview
)。嗯,这不是很必要。首次下载后,图像将在缓存中,因此任何进一步的图像请求都将快速完成。感谢缓存; Find image in in-memory cache
- &gt; Find image in file cache
- &gt; Downloading from server
。