从便携式类库存储文件(PCL)

验证

许多应用程序必须持续应用数据或状态。使用C#开发移动应用程序,例如用于iOS和Android的Windows或Xamarin,它是在便携式类库(PCL)中共享您的业务逻辑和后端实现的常用方法。在此博客文章中,我们将研究我们如何在PCL内实现存储,因此只需要实现一次存储服务。我们将重点关注以下主题:

  1. 设置项目
  2. 将对象存储和加载到文件
  3. 存储/使用诸如图像的二进制数据

所以让我们通过设置项目开始。我会用一个展示样本 xamarin.forms. 项目允许我在所有三个主要移动平台上快速开发,部署和测试应用程序。但由于代码在PCL中,您可以使用完全相同的方法来实现Windows Store,WPF等应用程序中的系统。

设置项目

让我们创建一个应用程序,按名称,URL列出公司,并显示公司徽标。为此,我们将创建一个显示内容的视图,如下所示:

<?xml version="1.0" encoding="utf-8" ?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"             x:Class="XamarinFormsOfflineStorage.Views.MainPage">  <Grid>  <Grid.RowDefinitions>    <RowDefinition Height="Auto"/>    <RowDefinition Height="*"/>  </Grid.RowDefinitions>  <Button Text="Refresh" Command="{Binding UpdateCompaniesCommand}"></Button>    <ListView ItemsSource="{Binding Companies}" Grid.Row="1">      <ListView.ItemTemplate>        <DataTemplate>          <ImageCell Text="{Binding Name}" ImageSource="{Binding ImageUri}" Detail="{Binding ImageDescription}"></ImageCell>        </DataTemplate>      </ListView.ItemTemplate>    </ListView>    <ActivityIndicator Grid.Row="1" IsRunning="{Binding IsLoadingData}"></ActivityIndicator>  </Grid></ContentPage>

数据由基于的视图模型提供 MVVM光 框架框架 Laurent Bugnion.。我刚刚在如何开始使用MVVM灯和Xamarin.forms开始发帖。

public class MainViewModel:ViewModelBase{    private readonly ICompanyService _companyService;    private bool _isLoadingData;    public MainViewModel(ICompanyService companyService)    {        if (companyService == null) throw new ArgumentNullException("companyService");        _companyService = companyService;        Companies = new ObservableCollection<Company>();        IsLoadingData = false;        UpdateCompaniesCommand = new RelayCommand(UpdateCompanies, () => !IsLoadingData);    }    public bool IsLoadingData    {        get { return _isLoadingData; }        set        {            if (value == _isLoadingData) return;            _isLoadingData = value;            RaisePropertyChanged(() => IsLoadingData);        }    }    public ObservableCollection<Company> Companies { get; set; }    public ICommand UpdateCompaniesCommand { get; set; }    public async Task Init()    {        await UpdateCompaniesList();    }    private async void UpdateCompanies()    {        IsLoadingData = true;        await _companyService.UpdateCompanies();        await UpdateCompaniesList();        IsLoadingData = false;    }    private async Task UpdateCompaniesList()    {        var companies = await _companyService.GetCompanies();        Companies.Clear();        foreach (var company in companies)        {            Companies.Add(company);        }    }}

呼叫A. CompanyService. 调用后端:

// ...public async Task UpdateCompanies(){    // URL should point to where your service is running    const string uri = "http://offlinestorageserver.azurewebsites.net/api/values";    var httpResult = await _httpClient.GetAsync(uri);    var jsonCompanies = await httpResult.Content.ReadAsStringAsync();    var companies = JsonConvert.DeserializeObject<ICollection<Models.Company>>(jsonCompanies);    _companies = companies;}// ...

并提供公司列表:

public IEnumerable<Models.Company> GetCompanies(){    return _companies;}

现在让我们看看我们如何将此列表存储到“磁盘”并显示信息,即使在没有连接到后端时启动应用程序也是如此。

在PCL中启用存储访问

谢谢 丹尼尔解释了 从应用程序的PCL中访问文件存储实际上非常简单。为我们提供的所有这些都是安装尼古特包 PCL储存。确保您不仅为PCL安装,而且仅适用于您所针对的应用程序的平台:

pclstoragenugetinstall.

在我们存储之前,让我们仍然很快就会看看我们实际想要存储文件的位置。 PCL存储提供了一个启动位置,可以通过调用来访问 filesystem.current.localstorage. 财产。这将返回一个 iFolder. 可以允许通过调用进一步的文件夹来导航到其他文件夹 getFolder. 方法,或者 创建文件夹 方法也可与碰撞选项一起使用 Openifexists.,我通常使用第二种方法,因为它允许编写更少的代码。因此,如果我们希望将数据存储在本地存储的根目录中的文件夹中,它将完成如下:

private static async Task<IFolder> NavigateToFolder(string targetFolder){    IFolder rootFolder = filesystem.current.localstorage.;    IFolder folder = await rootFolder.CreateFolderAsync(targetFolder,        CreationCollisionOption.OpenIfExists);    return folder;}

正如您可以看到PCL存储,因此良好地拥有异步/等待模式,因此在针对文件系统工作时不会阻止您的应用程序i.e.UI。现在让我们下来存放一些数据。

坚持物体

现在让我们首先存储我们从我们的服务中收到的对象列表到文件中。当我已经使用JSON.NET来解除来自我们服务的数据时,我将使用此库将我们的对象序列化为JSON字符串,然后将Now Text Data存储到文件中 SerializeCompanies. method:

private static async Task SerializeCompanies(IFolder folder, ICollection<Models.Company> companies){    IFile file = await folder.CreateFileAsync(CompaniesFileName, CreationCollisionOption.ReplaceExisting);    var companiesString = JsonConvert.SerializeObject(companies);    await file.WriteAllTextAsync(companiesString);}

正如您可以看到的,因此与文件夹相似地创建文件,但在碰撞选项中不同。通常,它通常更容易处理C#存储器世界本身中的数据合并(假设列表对此不大),然后只是覆盖预先存在的缓存。

加载数据对象

我们现在可以更新 康读 在我们称之为时返回列表的方法。

public async Task<IEnumerable<Models.Company>> GetCompanies(){    return _companies ?? (_companies = await ReadCompaniesFromFile.());}

一旦数据被网站持续到我们所做的那样,我们不再需要互联网连接来向用户提供信息。我们可以简单地从文件中读取它们 ReadCompaniesFromFile.:

private async Task<IEnumerable<Models.Company>>  ReadCompaniesFromFile.(){    var folder = await NavigateToFolder(CompaniesFolder);    if ((await folder.CheckExistsAsync(CompaniesFileName)) == ExistenceCheckResult.NotFound)    {        return new List<Models.Company>();    }    IFile file = await folder.GetFileAsync(CompaniesFileName);    var jsonCompanies = await file.ReadAllTextAsync();    if (string.IsNullOrEmpty(jsonCompanies)) return new List<Models.Company>();    var companies = JsonConvert.DeserializeObject<IEnumerable<Models.Company>>(jsonCompanies);    return companies;}

现在,对象数据被持续,但我们尚未存储不是文本数据但二进制数据的图像。所以让我们看看我们如何将图像存储到文件系统。

存储二进制数据

要存储图像,我们将必须获取图像并将二进制数据从Web存储到文件。这是使用** storeimageslocallyAndatePath **方法中的打开文件的文件流完成的

private async Task StoreImagesLocallyAndUpdatePath(IFolder folder, IEnumerable<Models.Company> companies){    foreach (var company in companies)    {        var file = await folder.CreateFileAsync(company.Name + ".jpg", CreationCollisionOption.ReplaceExisting);        using (var fileHandler = await file.OpenAsync(FileAccess.ReadAndWrite))        {            var httpResponse = await _httpClient.GetAsync(company.ImageUri);            byte[] imageBuffer = await httpResponse.Content.ReadAsByteArrayAsync();            await fileHandler.WriteAsync(imageBuffer, 0, imageBuffer.Length);            company.ImageUri = file.Path;        }    }}

应始终配置流,或者将发生内存泄漏,以便在使用块中包裹流。为了存储二进制数据,我们通过提供的URL下载图像并将内容读取到一个字节数组中,允许我们轻松将其传递到流中,以便存储它。最后,我们取代了 Imageuri. POCO(普通旧CLR对象)中的数据序列化。

我建议您根据您存储的数据使用文件结尾。某些容器依赖于信息,因此只要良好的做法保持不变,我们就不会运行必须调试在屏幕上未显示的信息的奇怪错误的风险。

加载图像

现在我们可以将图像加载到内存中,但由于图像有些特殊情况,本地路径/ Imageuri. 单独足以在图像控制中设置。因此,我们实际上不必在UI中更改任何代码,或者添加任何其他处理,因为图像控制只需从本地存储中加载图像。

结论

在此帖子中,我们看到了我们如何设置我们的项目,以直接从PCL中存储文件。我们将数据对象存储到文件中的数据对象,并进行以存储图像/二进制数据。我想一个粗心谢谢你是由于丹尼尔解释了他的工作,因为他的作品真的简化了持续来自PCL的数据。

您可以找到整个代码 GitHub..

参考

标题图片 Hannes博士Grobe. 在下面 Creative Commons V3

Updated: