我们在开发应用商店应用时,需要app具有缓存的功能,这样在离线模式下,仍能工作。我们选择的project为Hub。
这里采取的策略是:在HubPage.xaml.cs(之所以不选择App.xaml.cs,是为了能让用户一边操作界面一边进行下载)中,利用await异步编程,避免阻塞UI,先读取存有图片路径的JSON,然后解析该JSON得到每一张图片的URI,再根据URI下载图片,对于文字资源,直接下载JSON。这里要特别注意文件操作——文件权限,同时更要注意文件流的选取——如果选择不当会导致在下载图片时偶然性僵死。
在HubPage.xaml.cs中:
using Bing.Maps; using demo02.Common; using demo02.Data; using demo02.DataModel; using demo02.DataStructure; using demo02.Entity; using demo02.Helper; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Net.Http; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using WhereWeGo.Helper; using Windows.ApplicationModel.Search; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.Storage; using Windows.UI; using Windows.UI.Popups; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Navigation; //“中心页”项模板在 http://go.microsoft.com/fwlink/?LinkID=321224 上有介绍 namespace demo02 { public sealed partial class HubPage : Page { //一个容器,里面存有每个图片的url对象 //将JSON中存的图片的uri读取到PicArray,然后通过PicArray下载图片 private static OfflinePicArray PicArray { get; set; } private NavigationHelper navigationHelper; private ObservableDictionary defaultViewModel = new ObservableDictionary(); public HubPage() { this.InitializeComponent(); this.navigationHelper = new NavigationHelper(this); this.navigationHelper.LoadState += navigationHelper_LoadState; } private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e) { if (ConnectState.isConnected) //如果网络是连接的,进行缓存下载 { if (OfflineFirstFlag.isFirstEnter) //由于之后会多次进入HubPage页面,我们只应当在第一次进入页面时进行下载 { OfflineFirstFlag.isFirstEnter = false; //获得图片资源,先下载存有uri的JSON,再解析JSON,再通过解析出的uri下载图片 //获取存有用于离线模式下图片uri的JSON await HttpGetOfflinePICSJSON(); //获取存有老师和地域图片的url的JSON await HttpGetOfflineTeacherRegionJSON(); //获得第一部分图片 await HttpGetOfflingPicByUrl(); //获得第二部分图片 await HttpGetOfflingPicByUrl02(); //获得第三部分图片 await HttpGetOfflingPicByUrl03(); //获得第四部分图片 await HttpGetOfflingPicByUrl04(); //获得文字资源 //获得离线模式数据展示的来源JSON await HttpGetOfflineJSON(); } } } //向服务器请求最新的PICS JSON private async static Task HttpGetOfflinePICSJSON() { XDownload xmen = new XDownload(ServiceUrl.URL_OFFLINE_PICSJSON, XDownload.App, OfflineSubFolder.Name, ServiceUrl.PICSJSON_LOCALNAME); await xmen.GetDataAsync(); } private async static Task HttpGetOfflingPicByUrl() { try { StorageFolder storageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; StorageFolder folder = await storageFolder.GetFolderAsync(OfflineSubFolder.Name); StorageFile storageFile = await folder.GetFileAsync(ServiceUrl.PICSJSON_LOCALNAME); if (storageFile != null) { XDownload bigOverhead = new XDownload(); bigOverhead.Library = XDownload.App; bigOverhead.Myfolder = OfflineSubFolder.Name; // 获取指定的文件中的文本内容 string textContent = await FileIO.ReadTextAsync(storageFile, Windows.Storage.Streams.UnicodeEncoding.Utf8); PicArray = JsonConvert.DeserializeObject<OfflinePicArray>(textContent); foreach (OfflinePicUri onePic in PicArray.Images) { foreach (string picName in onePic.ShowImages) { if (picName != null) { bigOverhead.Uri = ServiceUrl.BASEURL_OFFLINE + onePic.ImageFolder + picName; System.Diagnostics.Debug.WriteLine(bigOverhead.Uri + "kakakakakakkakakak"); bigOverhead.Filename = picName; await bigOverhead.GetDataAsync(); } } } } catch(Exception ex) { } } private async static Task HttpGetOfflingPicByUrl02() { try { StorageFolder storageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; StorageFolder folder = await storageFolder.GetFolderAsync(OfflineSubFolder.Name); StorageFile storageFile = await folder.GetFileAsync(ServiceUrl.PICSJSON_LOCALNAME); if (storageFile != null) { XDownload bigOverhead = new XDownload(); bigOverhead.Library = XDownload.App; bigOverhead.Myfolder = OfflineSubFolder.Name; // 获取指定的文件中的文本内容 string textContent = await FileIO.ReadTextAsync(storageFile, Windows.Storage.Streams.UnicodeEncoding.Utf8); PicArray = JsonConvert.DeserializeObject<OfflinePicArray>(textContent); foreach (OfflinePicUri onePic in PicArray.Images) { if (onePic.TileImagePath != null) { bigOverhead.Uri = ServiceUrl.BASEURL_OFFLINE + onePic.ImageFolder + onePic.TileImagePath; bigOverhead.Filename = onePic.TileImagePath; await bigOverhead.GetDataAsync(); } } } } catch (Exception ex) { } } private async static Task HttpGetOfflingPicByUrl03() { try { StorageFolder storageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; StorageFolder folder = await storageFolder.GetFolderAsync(OfflineSubFolder.Name); StorageFile storageFile = await folder.GetFileAsync(ServiceUrl.PICSJSON_LOCALNAME); if (storageFile != null) { XDownload bigOverhead = new XDownload(); bigOverhead.Library = XDownload.App; bigOverhead.Myfolder = OfflineSubFolder.Name; // 获取指定的文件中的文本内容 string textContent = await FileIO.ReadTextAsync(storageFile, Windows.Storage.Streams.UnicodeEncoding.Utf8); PicArray = JsonConvert.DeserializeObject<OfflinePicArray>(textContent); foreach (OfflinePicUri onePic in PicArray.Images) { if (onePic.Badge != null) { bigOverhead.Uri = ServiceUrl.BASEURL_OFFLINE + onePic.ImageFolder + onePic.Badge; bigOverhead.Filename = onePic.Badge; await bigOverhead.GetDataAsync(); } } } } catch(Exception ex) { } } private async Task HttpGetOfflingPicByUrl04() { try { StorageFolder storageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; StorageFolder folder = await storageFolder.GetFolderAsync(OfflineSubFolder.Name); //接着下载老师和地域的图片 StorageFile storageFile01 = await folder.GetFileAsync(ServiceUrl.T_R_JSON_LOCALNAME); if (storageFile01 != null) { XDownload bigOverhead = new XDownload(); bigOverhead.Library = XDownload.App; bigOverhead.Myfolder = OfflineSubFolder.Name; // 获取指定的文件中的文本内容 string textContent = await FileIO.ReadTextAsync(storageFile01, Windows.Storage.Streams.UnicodeEncoding.Utf8); TRPic tr = new TRPic(); tr = JsonConvert.DeserializeObject<TRPic>(textContent); foreach (string onePic in tr.TeacherImages) { //开始下载图片 bigOverhead.Uri = ServiceUrl.BASEURL_OFFLINE + onePic; bigOverhead.Filename = TeaRegFilter.GetPicName(onePic); await bigOverhead.GetDataAsync(); } } }catch (Exception ex) { } } private async static Task HttpGetOfflineJSON() { XDownload xmen = new XDownload(ServiceUrl.URL_OFFLINE_JSON, XDownload.App, OfflineSubFolder.Name, ServiceUrl.JSON_LOCALNAME); await xmen.GetDataAsync(); } private async static Task HttpGetOfflineTeacherRegionJSON() { XDownload xmen = new XDownload(ServiceUrl.URL_OFFLINE_TEACHER_REGION_JSON, XDownload.App, OfflineSubFolder.Name, ServiceUrl.T_R_JSON_LOCALNAME); await xmen.GetDataAsync(); } } } using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Windows.Networking.BackgroundTransfer; using Windows.Storage; using Windows.Storage.Streams; namespace demo02.Helper { //该类的作用是将服务器端的文件uri通过http下载到本地指定目录,并命名 public class XDownload { public static string Documents = "Documents"; public static string Pictures = "Pictures"; public static string Music = "Music"; public static string Videos = "Videos"; public static string App = "App"; public XDownload() { this.Uri = ""; this.Library = ""; this.Myfolder = ""; this.Filename = ""; } public XDownload(String uri, String library, String myfolder, String filename) { this.Uri = uri; this.Library = library; this.Myfolder = myfolder; this.Filename = filename; } //不带返回值的Task public async Task GetDataAsync() { StorageFolder folder = null; try { switch (this.Library) { case "Documents": folder = KnownFolders.DocumentsLibrary; break; case "Pictures": folder = KnownFolders.PicturesLibrary; break; case "Music": folder = KnownFolders.MusicLibrary; break; case "Videos": folder = KnownFolders.VideosLibrary; break; case "App": folder = Windows.ApplicationModel.Package.Current.InstalledLocation; //C:\Users\tom\Documents\GitHub\wherewegov1\wherewego\demo02\bin\Debug\AppX break; default: System.Diagnostics.Debug.WriteLine("ERROR: Make sure you are using the four special library: Documents, Music, Videos, Pictures"); return; } if (this.Myfolder == "") { System.Diagnostics.Debug.WriteLine("ERROR: Make sure you input a valid subfolder"); return; } StorageFolder childFolder = await folder.CreateFolderAsync(this.Myfolder, CreationCollisionOption.OpenIfExists); if (this.Filename == "") { System.Diagnostics.Debug.WriteLine("ERROR: Make sure you input a valid filename"); return; } //Creates a new file in the current folder, and specifies what to do if //a file with the same name already exists in the current folder. StorageFile outputFile = await childFolder.CreateFileAsync(this.Filename, CreationCollisionOption.ReplaceExisting); //选择恰当的流,避免下载图片过程中僵死 var fs = await outputFile.OpenAsync(FileAccessMode.ReadWrite); HttpClientHandler handler = new HttpClientHandler(); handler.ClientCertificateOptions = ClientCertificateOption.Automatic; HttpClient hc = new HttpClient(handler); HttpResponseMessage response = await hc.GetAsync(this.Uri, HttpCompletionOption.ResponseHeadersRead); Stream stream = await response.Content.ReadAsStreamAsync(); IInputStream inputStream = stream.AsInputStream(); ulong totalBytesRead = 0; while (true) { // Read from the web. IBuffer buffer = new Windows.Storage.Streams.Buffer(1024); buffer = await inputStream.ReadAsync( buffer, buffer.Capacity, InputStreamOptions.None); if (buffer.Length == 0) { // 完成 break; } // 进度 totalBytesRead += buffer.Length; System.Diagnostics.Debug.WriteLine("Bytes read: {0}", totalBytesRead); // 写文件. await fs.WriteAsync(buffer); } inputStream.Dispose(); fs.Dispose(); } catch (Exception) { System.Diagnostics.Debug.WriteLine("ERROR: file download failed, tai can le"); } } public string Uri { get; set; } public string Library { get; set; } public string Myfolder { get; set; } public string Filename { get; set; } } }