如何在 ViewWillAppear 中使用 FFImageLoading?
How to use FFImageLoading in ViewWillAppear?
我想在顶部栏中显示一个 UIImageView,其中包含来自 url 的 UIImage,然后将其缓存在我的 iOS 本机 Xamarin iOS 应用程序中。问题是,当添加到 ViewWillAppear 时,FFImageLoading 日志显示图像被取消大约 10 次中有 9 次,但偶尔它会成功并显示。我使用:
ImageService.Instance.LoadUrl(url)
.Retry(3, 200)
.Into(avatarImage);
它要么在第一次尝试时成功,要么所有重试都失败(我也尝试过更长的重试延迟但没有成功)。如果我将代码放在 ViewDidAppear 中,它会在 10 次中工作 9 次,但并非总是如此,也不会在第一次加载时起作用。如果我将它放入我在视图加载后按下的按钮,图像总是加载成功。因此,FFImageLoading 失败似乎很明显,因为 UIImageView 尚未 drawn/loaded,但是当我创建 UIImageView 并将其添加到视图时,我不知道还能做什么。
如何使用 FFImageLoading 可靠地加载图像?我可以预加载它,但这仍然不能解决我在第一次显示之前如何将它放入 UIImageView 的问题。如果无法使用 FFImageLoading,我愿意接受其他选择。
日志:无法加载到 UIImageView:
[0:] FFImageLoadingDebug_SimpleDiskCache path: /var/mobile/Containers/Data/Application/93D1FA0C-B19A-4ECA-A0DA-B0AC408A5B8E/Library/Caches/FFSimpleDiskCache
Thread started: <Thread Pool> #3
Thread started: <Thread Pool> #4
Thread started: <Thread Pool> #5
Thread started: <Thread Pool> #6
Thread started: #7
Thread started: <Thread Pool> #8
Thread started: <Thread Pool> #9
Thread started: #10
Thread started: #11
Thread started: <Thread Pool> #12
Thread started: <Thread Pool> #13
[0:] FFImageLoadingDebug_Image memory cache size: 401,5 MB
[0:] FFImageLoadingDebug_Image loading cancelled: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_Generating/retrieving image: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Generating/retrieving image: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
Thread started: #14
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Image loading cancelled: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_File /var/mobile/Containers/Data/Application/93D1FA0C-B19A-4ECA-A0DA-B0AC408A5B8E/Library/Caches/FFSimpleDiskCache/CD275DFA133499968568338D6D522382.864000 saved to disk cache for key CD275DFA133499968568338D6D522382
[0:] FFImageLoadingDebug_Image loaded from cache: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
etc.
日志:成功(重新加载几次后同一页面):
[0:] FFImageLoadingDebug_Image loaded from cache: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_Image loaded from cache: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
etc.
参考official sample。可能会有帮助。
var taskImage = ImageService.Instance.LoadUrl(imageURL)
.ErrorPlaceholder("error.png", ImageSource.ApplicationBundle)
.LoadingPlaceholder("placeholder", ImageSource.CompiledResource);
if(transformation==0)
{
taskImage.Into(imageView);
transformation++;
}
else if(transformation==1)
{
taskImage.Transform(new CircleTransformation()).Into(imageView);
transformation++;
}
else if(transformation==2)
{
taskImage.Transform(new RoundedTransformation(10)).Into(imageView);
transformation = 0;
}
我一直无法弄清楚为什么 FFImageLoading 被取消,所以我使用 Akavache and HttpClient to roll my own (I also use CrossConnectivity 检查手机是否已连接)。
每次从 ViewWillAppear 更新时都有效。因为我使用 IObservable,所以在主线程 UI 上更新图像很重要,即 InvokeOnMainThread
.
UrlImageView class 用于添加可以从 Url 加载图像的 UIView:
public class UrlImageView : UIImageView
{
private GetImageFromUrlObserver getImageFromUrlObserver = null;
public UrlImageView() : base()
{
getImageFromUrlObserver = new GetImageFromUrlObserver(this);
}
public void GetImageFromUrl(string url)
{
if (getImageFromUrlObserver != null)
{
getImageFromUrlObserver.GetImage(url);
}
}
public void Update(byte[] image)
{
this.InvokeOnMainThread(() =>
{
var data = NSData.FromArray(image);
this.Image = UIImage.LoadFromData(data);
});
}
}
IObserver class(当获取图片数据时会触发OnNext
)
public class GetImageFromUrlObserver : IObserver<byte[]>
{
private UrlImageView urlImageView;
private IDisposable unsubscriber;
public GetImageFromUrlObserver(UrlImageView view)
{
urlImageView = view;
}
public void GetImage(string url)
{
Subscribe(ImageLoader.GetImageFromUrl(url));
}
private void Subscribe(IObservable<byte[]> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public void OnCompleted()
{
Unsubscribe();
}
public void OnError(Exception error)
{
throw new NotImplementedException();
}
public void OnNext(byte[] image)
{
if (urlImageView != null)
{
urlImageView.Update(image);
}
}
private void Unsubscribe()
{
if (unsubscriber != null)
{
urlImageView = null;
unsubscriber.Dispose();
unsubscriber = null;
}
}
}
获取图片数据的HttpClientclass:
public static class ImageLoader
{
public static IObservable<byte[]> GetImageFromUrl(string url)
{
IObservable<byte[]> result = null;
var httpClient = new HttpClient(new NativeMessageHandler());
});
try
{
var cache = BlobCache.LocalMachine;
result = cache.GetAndFetchLatest(
url, /* simply use url as cache key */
async () =>
{
try
{
if (!CrossConnectivity.Current.IsConnected) return null;
HttpResponseMessage httpResponse = await httpClient.GetAsync(url);
return await httpResponse.Content.ReadAsByteArrayAsync().ConfigureAwait(false); ;
}
catch (Exception e)
{
EventTrackers.TrackException("GetImageFromUrl inner - " + e.Message);
return null;
}
},
offset =>
{
TimeSpan elapsed = DateTimeOffset.Now - offset;
return elapsed > new TimeSpan(hours: cacheUpdateFrequencyHours, minutes: cacheUpdateFrequencyMinutes, seconds: 0);
}
);
}
catch (Exception e)
{
EventTrackers.TrackException("GetImageFromUrl - " + e.Message);
return null;
}
return result;
}
显示你调用的图片:
UrlImageView image = new UrlImageView();
View.AddSubview(image);
image.GetImageFromUrl(url);
我想在顶部栏中显示一个 UIImageView,其中包含来自 url 的 UIImage,然后将其缓存在我的 iOS 本机 Xamarin iOS 应用程序中。问题是,当添加到 ViewWillAppear 时,FFImageLoading 日志显示图像被取消大约 10 次中有 9 次,但偶尔它会成功并显示。我使用:
ImageService.Instance.LoadUrl(url)
.Retry(3, 200)
.Into(avatarImage);
它要么在第一次尝试时成功,要么所有重试都失败(我也尝试过更长的重试延迟但没有成功)。如果我将代码放在 ViewDidAppear 中,它会在 10 次中工作 9 次,但并非总是如此,也不会在第一次加载时起作用。如果我将它放入我在视图加载后按下的按钮,图像总是加载成功。因此,FFImageLoading 失败似乎很明显,因为 UIImageView 尚未 drawn/loaded,但是当我创建 UIImageView 并将其添加到视图时,我不知道还能做什么。
如何使用 FFImageLoading 可靠地加载图像?我可以预加载它,但这仍然不能解决我在第一次显示之前如何将它放入 UIImageView 的问题。如果无法使用 FFImageLoading,我愿意接受其他选择。
日志:无法加载到 UIImageView:
[0:] FFImageLoadingDebug_SimpleDiskCache path: /var/mobile/Containers/Data/Application/93D1FA0C-B19A-4ECA-A0DA-B0AC408A5B8E/Library/Caches/FFSimpleDiskCache
Thread started: <Thread Pool> #3
Thread started: <Thread Pool> #4
Thread started: <Thread Pool> #5
Thread started: <Thread Pool> #6
Thread started: #7
Thread started: <Thread Pool> #8
Thread started: <Thread Pool> #9
Thread started: #10
Thread started: #11
Thread started: <Thread Pool> #12
Thread started: <Thread Pool> #13
[0:] FFImageLoadingDebug_Image memory cache size: 401,5 MB
[0:] FFImageLoadingDebug_Image loading cancelled: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_Generating/retrieving image: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Generating/retrieving image: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
Thread started: #14
[0:] FFImageLoadingDebug_Wait for similar request for key: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
[0:] FFImageLoadingDebug_Image loading cancelled: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_File /var/mobile/Containers/Data/Application/93D1FA0C-B19A-4ECA-A0DA-B0AC408A5B8E/Library/Caches/FFSimpleDiskCache/CD275DFA133499968568338D6D522382.864000 saved to disk cache for key CD275DFA133499968568338D6D522382
[0:] FFImageLoadingDebug_Image loaded from cache: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
etc.
日志:成功(重新加载几次后同一页面):
[0:] FFImageLoadingDebug_Image loaded from cache: https://assets-cdn.github.com/images/modules/logos_page/Octocat.png;CircleTransformation,borderSize=0,borderHexColor=
[0:] FFImageLoadingDebug_Image loaded from cache: https://autodesk-forge.github.io/dist/sample.png?43fa010fd5f9a49ec978f5dec499349d
etc.
参考official sample。可能会有帮助。
var taskImage = ImageService.Instance.LoadUrl(imageURL)
.ErrorPlaceholder("error.png", ImageSource.ApplicationBundle)
.LoadingPlaceholder("placeholder", ImageSource.CompiledResource);
if(transformation==0)
{
taskImage.Into(imageView);
transformation++;
}
else if(transformation==1)
{
taskImage.Transform(new CircleTransformation()).Into(imageView);
transformation++;
}
else if(transformation==2)
{
taskImage.Transform(new RoundedTransformation(10)).Into(imageView);
transformation = 0;
}
我一直无法弄清楚为什么 FFImageLoading 被取消,所以我使用 Akavache and HttpClient to roll my own (I also use CrossConnectivity 检查手机是否已连接)。
每次从 ViewWillAppear 更新时都有效。因为我使用 IObservable,所以在主线程 UI 上更新图像很重要,即 InvokeOnMainThread
.
UrlImageView class 用于添加可以从 Url 加载图像的 UIView:
public class UrlImageView : UIImageView
{
private GetImageFromUrlObserver getImageFromUrlObserver = null;
public UrlImageView() : base()
{
getImageFromUrlObserver = new GetImageFromUrlObserver(this);
}
public void GetImageFromUrl(string url)
{
if (getImageFromUrlObserver != null)
{
getImageFromUrlObserver.GetImage(url);
}
}
public void Update(byte[] image)
{
this.InvokeOnMainThread(() =>
{
var data = NSData.FromArray(image);
this.Image = UIImage.LoadFromData(data);
});
}
}
IObserver class(当获取图片数据时会触发OnNext
)
public class GetImageFromUrlObserver : IObserver<byte[]>
{
private UrlImageView urlImageView;
private IDisposable unsubscriber;
public GetImageFromUrlObserver(UrlImageView view)
{
urlImageView = view;
}
public void GetImage(string url)
{
Subscribe(ImageLoader.GetImageFromUrl(url));
}
private void Subscribe(IObservable<byte[]> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public void OnCompleted()
{
Unsubscribe();
}
public void OnError(Exception error)
{
throw new NotImplementedException();
}
public void OnNext(byte[] image)
{
if (urlImageView != null)
{
urlImageView.Update(image);
}
}
private void Unsubscribe()
{
if (unsubscriber != null)
{
urlImageView = null;
unsubscriber.Dispose();
unsubscriber = null;
}
}
}
获取图片数据的HttpClientclass:
public static class ImageLoader
{
public static IObservable<byte[]> GetImageFromUrl(string url)
{
IObservable<byte[]> result = null;
var httpClient = new HttpClient(new NativeMessageHandler());
});
try
{
var cache = BlobCache.LocalMachine;
result = cache.GetAndFetchLatest(
url, /* simply use url as cache key */
async () =>
{
try
{
if (!CrossConnectivity.Current.IsConnected) return null;
HttpResponseMessage httpResponse = await httpClient.GetAsync(url);
return await httpResponse.Content.ReadAsByteArrayAsync().ConfigureAwait(false); ;
}
catch (Exception e)
{
EventTrackers.TrackException("GetImageFromUrl inner - " + e.Message);
return null;
}
},
offset =>
{
TimeSpan elapsed = DateTimeOffset.Now - offset;
return elapsed > new TimeSpan(hours: cacheUpdateFrequencyHours, minutes: cacheUpdateFrequencyMinutes, seconds: 0);
}
);
}
catch (Exception e)
{
EventTrackers.TrackException("GetImageFromUrl - " + e.Message);
return null;
}
return result;
}
显示你调用的图片:
UrlImageView image = new UrlImageView();
View.AddSubview(image);
image.GetImageFromUrl(url);