Xamarin.Forms DependencyService 注册和解析
使用 Xamarin.FormsDependencyService
调用本机平台功能时,必须通过 DependencyService
来注册平台实现,然后从共享代码进行解析,才能调用它们。
注册平台实现
必须通过 DependencyService
注册平台实现,Xamarin.Forms 在运行时才可以找到它们。
可以使用 DependencyAttribute
、Register
和 RegisterSingleton
方法执行注册。
重要
使用 NET 本机编译的 UWP 项目的版本生成应使用 Register
方法注册平台实现。
使用属性注册
可以使用 DependencyAttribute
通过 DependencyService
注册平台实现。 此属性指示指定的类型可提供接口的具体实现。
下面的示例使用 DependencyAttribute
来注册 IDeviceOrientationService
接口的 iOS 实现:
using Xamarin.Forms;
[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
...
}
}
}
在此示例中,DependencyAttribute
通过 DependencyService
注册 DeviceOrientationService
。 这样就会在具体类型所实现的接口上注册它。
同样,其他平台上的 IDeviceOrientationService
接口的实现也应通过 DependencyAttribute
注册。
注意
在命名空间级别完成使用 DependencyAttribute
注册。
使用方法注册
可以使用 DependencyService.Register
方法和 RegisterSingleton
方法向 DependencyService
注册平台实现。
下面的示例使用 Register
方法来注册 IDeviceOrientationService
接口的 iOS 实现:
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
DependencyService.Register<IDeviceOrientationService, DeviceOrientationService>();
return base.FinishedLaunching(app, options);
}
}
在此示例中,Register
在 IDeviceOrientationService
接口上注册具体类型 DeviceOrientationService
。 也可以使用 Register
方法的重载通过 DependencyService
注册平台实现:
DependencyService.Register<DeviceOrientationService>();
在此示例中,Register
方法使用 DependencyService
注册 DeviceOrientationService
。 这样就会在具体类型所实现的接口上注册它。
或者,可以使用 RegisterSingleton
方法将现有对象实例注册为单一实例:
var service = new DeviceOrientationService();
DependencyService.RegisterSingleton<IDeviceOrientationService>(service);
在此示例中,RegisterSingleton
方法针对 IDeviceOrientationService
接口将 DeviceOrientationService
对象实例注册为单一实例。
同样,其他平台上的 IDeviceOrientationService
接口的实现也可以使用 Register
方法或 RegisterSingleton
方法注册。
重要
必须在平台项目中使用 Register
和 RegisterSingleton
方法执行注册,才可以从共享代码调用平台实现提供的功能。
解析平台实现
必须先解析平台实现,然后才能调用它们。 通常使用 DependencyService.Get<T>
方法在共享代码中完成此操作。 不过也可以使用 DependencyService.Resolve<T>
方法完成它。
默认情况下,DependencyService
仅解析具有无参数构造函数的平台实现。 但是,依赖项解析方法可以注入到使用依赖项注入容器或工厂方法的 Xamarin.Forms 中,以解析平台实现。 这种方法可用于解析具有带有参数的构造函数的平台实现。 有关详细信息,请参阅 Xamarin.Forms 中的依赖项解析。
重要
如果调用的平台实现尚未通过 DependencyService
注册,将引发 NullReferenceException
。
使用 Get<T> 方法解析
Get<T>
方法在运行时检索接口 T
的平台实现,或者:
- 将它的实例创建为单一实例。
- 返回一个作为单一实例的现有实例,该实例已使用
RegisterSingleton
方法向DependencyService
注册。
在这两种情况下,在应用程序的生存期期间,此实例将持续存在,并且为解析同一平台实现而执行的所有后续调用将检索同一实例。
下面的代码示例说明了如何调用 Get<T>
方法解析 IDeviceOrientationService
接口并调用 GetOrientation
方法:
IDeviceOrientationService service = DependencyService.Get<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();
也可以将此代码压缩到一行:
DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();
注意
默认情况下,Get<T>
方法返回接口 T
的平台实现实例并将其作为单一实例。 但是,可以更改这种行为。 有关详细信息,请参阅管理解析对象的生存期。
使用 Resolve<T> 方法解析
Resolve<T>
方法在运行时使用 DependencyResolver
类注入到 Xamarin.Forms 的依赖项解析方法检索接口 T
的平台实现。 如果未将依赖项解析方法注入到 Xamarin.Forms,Resolve<T>
方法将回退到调用 Get<T>
方法,以检索平台实现。 有关将依赖项解析方法注入到 Xamarin.Forms 的详细信息,请参阅 Xamarin.Forms 中的依赖项解析。
下面的代码示例说明了如何调用 Resolve<T>
方法解析 IDeviceOrientationService
接口并调用 GetOrientation
方法:
IDeviceOrientationService service = DependencyService.Resolve<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();
也可以将此代码压缩到一行:
DeviceOrientation orientation = DependencyService.Resolve<IDeviceOrientationService>().GetOrientation();
注意
默认情况下,当 Resolve<T>
方法回退到调用 Get<T>
方法时,它将返回接口 T
的平台实现实例并将其作为单一实例。 但是,可以更改这种行为。 有关详细信息,请参阅管理解析对象的生存期。
管理解析对象的生存期
DependencyService
类的默认行为是将平台实现解析为单一实例。 因此,平台实现将在应用程序的生存期期间持续存在。
此行为由 Get<T>
和 Resolve<T>
方法上的可选参数 DependencyFetchTarget
指定。 DependencyFetchTarget
枚举定义以下两个成员:
- 将平台实现作为单一实例返回的
GlobalInstance
。 - 返回新的平台实现实例的
NewInstance
。 然后由应用程序负责管理平台实现实例的生存期。
Get<T>
和 Resolve<T>
方法均将其可选参数设置为 DependencyFetchTarget.GlobalInstance
,因此始终会将平台实现解析为单一实例。 通过将 DependencyFetchTarget.NewInstance
指定为 Get<T>
和 Resolve<T>
方法的参数,可以更改此行为,来创建新的平台实现实例:
ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
在此示例中,DependencyService
创建 ITextToSpeechService
接口的平台实现的新实例。 为解析 ITextToSpeechService
而执行的所有后续调用也将创建新实例。
始终创建新的平台实现实例的结果是由应用程序负责管理实例的生存期。 这意味着,如果订阅平台实现定义的事件,不再需要此平台实现时,应取消订阅此事件。 此外,这意味着,平台实现可能需要实现 IDisposable
并在 Dispose
方法中清除这些资源。 示例应用程序在其 TextToSpeechService
平台实现中演示了此方案。
如果应用程序不再使用实现 IDisposable
的平台实现,它应调用对象的 Dispose
实现。 完成此操作的方式之一是使用 using
语句:
ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
using (service as IDisposable)
{
await service.SpeakAsync("Hello world");
}
在此示例中,调用 SpeakAsync
方法后,using
语句自动释放平台实现对象。 这样就会调用对象的 Dispose
方法,来执行必需的清理。
有关调用对象的 Dispose
方法的详细信息,请参阅使用实现 IDisposable 的对象。