Xamarin.Forms DependencyService 无法在文件处理中跨平台共享接口
Xamarin.Forms DependencyService cannot share interface cross-platform in file handling
我正在关注 official Xamarin guide 使用 .net-standard-2.0
PCL 项目进行跨平台文件处理。该应用程序旨在为 Android 和 Windows.
构建
这让我想到了一个问题。接口代码如下
public interface ISaveAndLoad {
void SaveText (string filename, string text);
string LoadText (string filename);
}
然而,UWP给出的代码写成
[assembly: Dependency(typeof(SaveAndLoad_WinApp))]
namespace WindowsApp
{
// https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh758325.aspx
public class SaveAndLoad_WinApp : ISaveAndLoad
{
public async Task SaveTextAsync(string filename, string text)
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await localFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(sampleFile, text);
}
public async Task<string> LoadTextAsync(string filename)
{
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await storageFolder.GetFileAsync(filename);
string text = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
return text;
}
}
}
代码将无法编译,因为 SaveAndLoad_WinApp
未实现接口 ISaveAndLoad
。
我知道我可以将界面更改为Task
和Task<string>
,所以它会编译。
然而问题又回到了Android。
UWP 正在使用这个 Windows.Storage.FileIO
在 Android 上不存在的东西。当 Android 使用 System.IO
时,它没有可以等待的异步方法。这意味着我无法共享界面,因为 UWP 需要 async Task<string>
但 Android 仅 return 是 string
而不是 Task
。
如果我不在 UWP 方法中使用 async
,则 FileIO
将不起作用,反之亦然。 async void
for SaveText
工作正常,因为界面状态为 void
。但是,它不允许我为 LoadText
创建 async string
,因为异步方法必须 return a Task<T>
、Task
或 void
。
似乎要走的路也会在 Android 上实现异步,同时让代码 运行 同步。但是,我觉得我做错了什么,因为 Xamarin 示例显示它应该可以工作。
我是不是误解了什么或者遗漏了一个实现?或者它在 Xamarin 文档中实际上是错误的?
更新#1
我已经为 SaveText
设置了 async void
并意识到存在未等待线程的问题。它快速转发到下一个功能。所以我实际上必须等待 UWP PCL 中的函数。然而,Android 上的实施是无法等待的 void
。所以它实际上导致了错误......
对如何实现这个场景有什么建议吗?
这是我在 PCL
中输入的代码
public static void Save(){
DependencyService.Get<ISaveAndLoad>().SaveText("temp.txt", input.Text);
}
The code will not compile as SaveAndLoad_WinApp does not implement the interface ISaveAndLoad.
您可以下载文档示例WorkingWithFiles, you could find it here. In this sample the ISaveAndLoad界面有点不同:
public interface ISaveAndLoad
{
Task SaveTextAsync (string filename, string text);
Task<string> LoadTextAsync (string filename);
bool FileExists (string filename);
}
UWP is using this Windows.Storage.FileIO thing which does not exists on Android. While Android is using System.IO, it does not have a Async method that can be awaited.
可以参考SaveAndLoad_Android.cs class in the sample project, use StreamWriter.WriteAsync()方法:
public class SaveAndLoad_Android : ISaveAndLoad
{
#region ISaveAndLoad implementation
public async Task SaveTextAsync (string filename, string text)
{
var path = CreatePathToFile (filename);
using (StreamWriter sw = File.CreateText (path))
await sw.WriteAsync(text);
}
public async Task<string> LoadTextAsync (string filename)
{
var path = CreatePathToFile (filename);
using (StreamReader sr = File.OpenText(path))
return await sr.ReadToEndAsync();
}
public bool FileExists(string filename)
{
return File.Exists(CreatePathToFile(filename));
}
#endregion
string CreatePathToFile(string filename)
{
var docsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
return Path.Combine(docsPath, filename);
}
}
然后在您的 PCL
中使用 SaveTextAsync 方法,如下所示:
var fileService = DependencyService.Get<ISaveAndLoad> ();
...
saveButton.Clicked += async (sender, e) =>
{
loadButton.IsEnabled = saveButton.IsEnabled = false;
// uses the Interface defined in this project, and the implementations that must
// be written in the iOS, Android and WinPhone app projects to do the actual file manipulation
await fileService.SaveTextAsync (fileName, input.Text);
loadButton.IsEnabled = saveButton.IsEnabled = true;
};
我正在关注 official Xamarin guide 使用 .net-standard-2.0
PCL 项目进行跨平台文件处理。该应用程序旨在为 Android 和 Windows.
这让我想到了一个问题。接口代码如下
public interface ISaveAndLoad {
void SaveText (string filename, string text);
string LoadText (string filename);
}
然而,UWP给出的代码写成
[assembly: Dependency(typeof(SaveAndLoad_WinApp))]
namespace WindowsApp
{
// https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh758325.aspx
public class SaveAndLoad_WinApp : ISaveAndLoad
{
public async Task SaveTextAsync(string filename, string text)
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await localFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(sampleFile, text);
}
public async Task<string> LoadTextAsync(string filename)
{
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await storageFolder.GetFileAsync(filename);
string text = await Windows.Storage.FileIO.ReadTextAsync(sampleFile);
return text;
}
}
}
代码将无法编译,因为 SaveAndLoad_WinApp
未实现接口 ISaveAndLoad
。
我知道我可以将界面更改为Task
和Task<string>
,所以它会编译。
然而问题又回到了Android。
UWP 正在使用这个 Windows.Storage.FileIO
在 Android 上不存在的东西。当 Android 使用 System.IO
时,它没有可以等待的异步方法。这意味着我无法共享界面,因为 UWP 需要 async Task<string>
但 Android 仅 return 是 string
而不是 Task
。
如果我不在 UWP 方法中使用 async
,则 FileIO
将不起作用,反之亦然。 async void
for SaveText
工作正常,因为界面状态为 void
。但是,它不允许我为 LoadText
创建 async string
,因为异步方法必须 return a Task<T>
、Task
或 void
。
似乎要走的路也会在 Android 上实现异步,同时让代码 运行 同步。但是,我觉得我做错了什么,因为 Xamarin 示例显示它应该可以工作。
我是不是误解了什么或者遗漏了一个实现?或者它在 Xamarin 文档中实际上是错误的?
更新#1
我已经为 SaveText
设置了 async void
并意识到存在未等待线程的问题。它快速转发到下一个功能。所以我实际上必须等待 UWP PCL 中的函数。然而,Android 上的实施是无法等待的 void
。所以它实际上导致了错误......
对如何实现这个场景有什么建议吗?
这是我在 PCL
中输入的代码public static void Save(){
DependencyService.Get<ISaveAndLoad>().SaveText("temp.txt", input.Text);
}
The code will not compile as SaveAndLoad_WinApp does not implement the interface ISaveAndLoad.
您可以下载文档示例WorkingWithFiles, you could find it here. In this sample the ISaveAndLoad界面有点不同:
public interface ISaveAndLoad
{
Task SaveTextAsync (string filename, string text);
Task<string> LoadTextAsync (string filename);
bool FileExists (string filename);
}
UWP is using this Windows.Storage.FileIO thing which does not exists on Android. While Android is using System.IO, it does not have a Async method that can be awaited.
可以参考SaveAndLoad_Android.cs class in the sample project, use StreamWriter.WriteAsync()方法:
public class SaveAndLoad_Android : ISaveAndLoad
{
#region ISaveAndLoad implementation
public async Task SaveTextAsync (string filename, string text)
{
var path = CreatePathToFile (filename);
using (StreamWriter sw = File.CreateText (path))
await sw.WriteAsync(text);
}
public async Task<string> LoadTextAsync (string filename)
{
var path = CreatePathToFile (filename);
using (StreamReader sr = File.OpenText(path))
return await sr.ReadToEndAsync();
}
public bool FileExists(string filename)
{
return File.Exists(CreatePathToFile(filename));
}
#endregion
string CreatePathToFile(string filename)
{
var docsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
return Path.Combine(docsPath, filename);
}
}
然后在您的 PCL
中使用 SaveTextAsync 方法,如下所示:
var fileService = DependencyService.Get<ISaveAndLoad> ();
...
saveButton.Clicked += async (sender, e) =>
{
loadButton.IsEnabled = saveButton.IsEnabled = false;
// uses the Interface defined in this project, and the implementations that must
// be written in the iOS, Android and WinPhone app projects to do the actual file manipulation
await fileService.SaveTextAsync (fileName, input.Text);
loadButton.IsEnabled = saveButton.IsEnabled = true;
};