【问题标题】:Image Caching in Windows Phone 8.1Windows Phone 8.1 中的图像缓存
【发布时间】:2017-02-16 17:50:32
【问题描述】:

我正在编写一个 Windows Phone 8.1 (WINRT) 应用程序。 它显示从互联网获取的图像。

我想将此图像保存到本地存储,然后再显示。 我的意思是,每次应用程序打开时,它都会检查图像是否在本地存储中,显示它并从互联网并行加载该图像的新副本,并将 ui 刷新到新图像。

意味着,在从 Internet 加载图像的新副本之前,从本地存储中获取的该图像的缓存副本将充当 占位符

但问题是我得到空白 UI,直到图像从互联网加载,而不是本地图像充当占位符。

C#

public sealed partial class ProfileView : Page
{
    const string PROFILE_PIC_FILE_NAME = "UmangProfilePic.jpg";
    public ProfileView()
    {
        this.InitializeComponent();

        this.NavigationCacheMode = NavigationCacheMode.Required;
    }


    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        //Testing:
        //string url = "http://www.nokia.com/sites/default/files/styles/medium/public/media/nokia_white_logo.png"; //small image
        string url = "http://anderson.chem.ox.ac.uk/images/group2015.jpg"; //large image

        await UmangImageCacheAsync(url);
    }

    /// <summary>
    /// Check if image exists in local storage, load that image to UI control
    /// Then, get latest image from internet and storage that image in local storage
    /// Then, load that new image from local storage again to UI control
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    private async Task UmangImageCacheAsync(string url)
    {
        loadingProfilePic.IsActive = true;

        //var dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
        //var ignored = dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
        //{


        //});

        var dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
        var ignored = dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
        {
            if (await FileExists(PROFILE_PIC_FILE_NAME))
            {
                profilePicImage.Source = await GetLocalImageAsync();
            }
        });

        var result = await GetRemoteImageAsync(url);

        if (result is BitmapImage)
        {
            profilePicImage.Source = result as BitmapImage;
            loadingProfilePic.IsActive = false;
        }
        else
        {
            loadingProfilePic.IsActive = false;
        }




    }

    private async Task<BitmapImage> GetLocalImageAsync()
    //  private async Task<bool> GetLocalImageAsync()
    {
        StorageFolder localFolder = ApplicationData.Current.LocalFolder;
        StorageFile file = await localFolder.GetFileAsync(PROFILE_PIC_FILE_NAME);
        var image = await FileIO.ReadBufferAsync(file);
        Uri uri = new Uri(file.Path);
        return new BitmapImage(new Uri(file.Path));

        //return true;
    }

    private static async Task<object> GetRemoteImageAsync(string url)
    //private static async Task GetRemoteImageAsync(string url)
    {
        StorageFolder localFolder = ApplicationData.Current.LocalFolder;
        StorageFile file = await localFolder.CreateFileAsync(PROFILE_PIC_FILE_NAME, CreationCollisionOption.ReplaceExisting);

        HttpClient client = new HttpClient();

        try
        {
            byte[] responseBytes = await client.GetByteArrayAsync(url);

            var stream = await file.OpenAsync(FileAccessMode.ReadWrite);

            using (var outputStream = stream.GetOutputStreamAt(0))
            {
                DataWriter writer = new DataWriter(outputStream);
                writer.WriteBytes(responseBytes);
                await writer.StoreAsync();
                await outputStream.FlushAsync();
            }
            var image = await FileIO.ReadBufferAsync(file);
            Uri uri = new Uri(file.Path);
            return new BitmapImage(new Uri(file.Path));

        }
        catch (Exception _ex)
        {
            return false;
        }
    }


    public static async Task<bool> FileExists(string fileName)
    {
        StorageFolder localFolder = ApplicationData.Current.LocalFolder;
        try
        {
            StorageFile file = await localFolder.GetFileAsync(fileName);
        }
        catch (Exception _fileEx)
        {
            return false;
        }
        return true;
    }
}

XAML:

<Grid>
    <Grid>
        <Image
        x:Name="profilePicImage"
        Width="400"
        Height="400" />

        <ProgressRing x:Name="loadingProfilePic"
        IsActive="False"
        IsEnabled="True" >

        </ProgressRing>
    </Grid>
</Grid>

重现此问题:使用第一个“url”(小图像)执行应用程序, 然后再次使用第二个 url 调试第一个 url 直到 从互联网下载新图像,第一张图像应作为 占位符,但您将观察到的只是进度环

【问题讨论】:

  • 您可以随时尝试使用来自coding4fun.codeplex.com 的 SuperImage 控件,它有一个占位符选项,在 Internet 加载新内容时应显示的内容

标签: c# windows-phone-8 windows-phone-8.1 windows-phone


【解决方案1】:

您对 GetLocalImageAsync() 的调用在调用 GetRemoteImageAsync() 之后执行,因为您将其发布到调度程序队列。我认为您希望以相反的方式完成您的方案。

谢谢, Stefan Wick - Windows 开发者平台

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多