第二十章:非同步和檔案I/O.(十二)
雖然每個方法都被定義為返回Task或Task 物件,但是方法的主體沒有任何對Task或Task 的引用。相反,返回Task物件的方法只是執行一些工作,然後使用隱式return語句結束該方法。 ExistsAsync方法定義為返回Task 但返回true或false。 (StorageFolder類中沒有Exists方法,因此需要使用try和catch進行解決方法。)
類似地,ReadTextAsync方法被定義為返回Task ,但是body返回一個字串,該字串是通過將await運算子應用於File.ReadTextAsync的IAsyncOperation 返回值而獲得的。 C#編譯器執行必要的轉換。
當程式呼叫此ReadTextAsync方法時,該方法將執行,直到第一個await運算子,然後它將一個Task 物件返回給呼叫者。當FileIO.ReadTextAsync方法完成時,呼叫者可以使用ContinueWith或await來獲取字串。
但是,對於iOS和Android,我們現在遇到了問題。現在,IFileHelper中的所有方法都被定義為返回Task或Task 物件的非同步方法,但我們已經看到System.IO名稱空間中的方法不是非同步的。我們做什麼?
iOS名稱空間中的FileHelper類使用兩種策略。 在某些情況下,System.IO類確實包含非同步方法。 Stream Writer的WriteAsync方法和StreamReader的ReadAsync方法就是這種情況。 但是,對於其他方法,使用Task 的靜態FromResult方法將物件或值轉換為Task 物件以獲取方法返回值。 這實際上並不是將方法轉換為非同步方法,而只是允許方法具有同步方法的簽名:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Xamarin.Forms; [assembly: Dependency(typeof(Xamarin.FormsBook.Platform.iOS.FileHelper))] namespace Xamarin.FormsBook.Platform.iOS { class FileHelper : IFileHelper { public Task<bool> ExistsAsync(string filename) { string filepath = GetFilePath(filename); bool exists = File.Exists(filepath); return Task<bool>.FromResult(exists); } public async Task WriteTextAsync(string filename, string text) { string filepath = GetFilePath(filename); using (StreamWriter writer = File.CreateText(filepath)) { await writer.WriteAsync(text); } } public async Task<string> ReadTextAsync(string filename) { string filepath = GetFilePath(filename); using (StreamReader reader = File.OpenText(filepath)) { return await reader.ReadToEndAsync(); } } public Task<IEnumerable<string>> GetFilesAsync() { // Sort the filenames. IEnumerable<string> filenames = from filepath in Directory.EnumerateFiles(GetDocsFolder()) select Path.GetFileName(filepath); return Task<IEnumerable<string>>.FromResult(filenames); } public Task DeleteAsync(string filename) { File.Delete(GetFilePath(filename)); return Task.FromResult(true); } string GetDocsFolder() { return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); } string GetFilePath(string filename) { return Path.Combine(GetDocsFolder(), filename); } } }
Android FileHelper類與iOS類相同,但具有不同的名稱空間。
請注意,這些平臺實現中唯一的錯誤檢查是Windows執行時平臺中的ExistsAsync方法,它使用異常來確定檔案是否存在。 沒有其他方法 - 特別是WriteTextAsync和ReadTextAsync
方法 - 正在執行任何錯誤檢查。 使用await的一個很好的功能是,當你實際呼叫這些方法時,可以在以後捕獲任何異常。
您可能還注意到,各個GetFilesAsync方法現在正在從完全限定的檔名中刪除路徑,因此該作業不需要由Xamarin.FormsBook.Platform專案中的FileHelper類執行:
namespace Xamarin.FormsBook.Platform { class FileHelper { IFileHelper fileHelper = DependencyService.Get<IFileHelper>(); public Task<bool> ExistsAsync(string filename) { return fileHelper.ExistsAsync(filename); } public Task WriteTextAsync(string filename, string text) { return fileHelper.WriteTextAsync(filename, text); } public Task<string> ReadTextAsync(string filename) { return fileHelper.ReadTextAsync(filename); } public Task<IEnumerable<string>> GetFilesAsync() { return fileHelper.GetFilesAsync(); } public Task DeleteAsync(string filename) { return fileHelper.DeleteAsync(filename); } } }
現在我們有了一個庫,我們需要從一個應用程式訪問這個庫。 TextFileAsync解決方案是正常建立的。 然後,Xamarin.FormsBook.Platform解決方案中的所有七個專案都新增到此解決方案中。 必須使用解決方案的“新增和現有專案”選單項單獨新增這些專案。 解決方案選單項中沒有新增所有專案,但如果您在自己的專案中使用這些庫,您會希望有!
此時,TextFileAsync解決方案包含13個專案:五個應用程式專案,一個包含應用程式程式碼的共享PCL和七個庫專案。
必須使用Reference Manager為以下關係在這些專案之間建立引用:
- TextFileAsync引用了Xamarin.FormsBook.Platform。
- TextFileAsync.iOS引用了Xamarin.FormsBook.Platform.iOS。
- TextFileAsync.Droid引用了Xamarin.FormsBook.Platform.Android。
- TextFileAsync.UWP引用了Xamarin.FormsBook.Platform.UWP。
- TextFileAsync.Windows引用了Xamarin.FormsBook.Platform.Windows。
- TextFileAsync.WinPhone引用了Xamarin.FormsBook.Platform.WinPhone。
當然,所有應用程式專案都有對TextFileAsync PCL的正常引用,並且,正如您所記得的,Xamarin.FormsBook.Platform.UWP,Windows和WinPhone專案都引用了共享的Xamarin.FormsBook.Platform.WinRT 專案。
此外,所有TextFileAsync專案都應該呼叫庫中的各種Toolkit.Init方法。 在TextFileAsync專案本身中,在App類的建構函式中進行呼叫:
namespace TextFileAsync
{
public class App : Application
{
public App()
{
Xamarin.FormsBook.Platform.Toolkit.Init();
__
}
__
}
}
在iOS專案中,在AppDelegate類中正常的Forms.Init呼叫之後進行呼叫:
namespace TextFileAsync.iOS
{
__
public partial class AppDelegate :
global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
__
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
Xamarin.FormsBook.Platform.iOS.Toolkit.Init();
LoadApplication(new App());
__
}
}
}
在Android專案中,在正常的Forms.Init呼叫之後,使用MainActivity類中的MainActivity和Bundle物件呼叫Toolkit.Init:
namespace TextFileAsync.Droid
{
__
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
protected override void OnCreate(Bundle bundle)
{
__
global::Xamarin.Forms.Forms.Init(this, bundle);
Xamarin.FormsBook.Platform.Android.Toolkit.Init(this, bundle);
LoadApplication(new App());
}
}
}
在Windows平臺中,在App.xaml.cs檔案中的Forms.Init之後立即呼叫Toolkit.Init:
namespace TextFileAsync.UWP
{
__
sealed partial class App : Application
{
__
Xamarin.Forms.Forms.Init(e);
Xamarin.FormsBook.Platform.UWP.Toolkit.Init();
__
}
}
好久沒更新系列部落格了,對不起大家了。今天接著來。大家要是喜歡,支援一下