DependencyService
类是允许 Xamarin.Forms 应用程序从共享代码 调用本机平台功能的服务定位器。
必须使用 DependencyService
注册平台实现,然后从共享代码进行解析,才能调用它们。
用DependencyService的理由:
由于 Xamarin.Forms 不包含此功能,因此有必要使用 DependencyService
来访问每个平台上的本机 API。
介绍
使用 DependencyService
调用本机平台功能的过程用于:
- 在共享代码中创建本机平台功能的接口。 有关详细信息,请参阅创建接口。
- 在所需的平台项目中实现此接口。 有关详细信息,请参阅在各个平台上实现接口。
- 通过
DependencyService
注册平台实现,这样 Xamarin.Forms 即可以在运行时找到平台实现。 有关详细信息,请参阅注册平台实现。 - 从共享代码解析平台实现,并调用它们。 有关详细信息,请参阅解析平台实现。
下图说明了如何在 Xamarin.Forms 应用程序中调用本机平台功能:
1、创建接口
若要能够从共享代码调用本机平台功能,第一个步骤是创建接口来定义与本机平台功能交互的 API。 应将此接口置于共享代码项目中。
下面的示例说明了可用于检索设备方向的 API 接口:
public interface IDeviceOrientationService { DeviceOrientation GetOrientation(); }
2、在各个平台上实现此接口
创建定义与本机平台功能交互的 API 的接口后,必须在各个平台项目中实现此接口。
Android
下面的代码示例演示 Android 上的 IDeviceOrientationService
接口实现:
namespace DependencyServiceDemos.Droid { public class DeviceOrientationService : IDeviceOrientationService { public DeviceOrientation GetOrientation() { IWindowManager windowManager = Android.App.Application.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>(); SurfaceOrientation orientation = windowManager.DefaultDisplay.Rotation; bool isLandscape = orientation == SurfaceOrientation.Rotation90 || orientation == SurfaceOrientation.Rotation270; return isLandscape ? DeviceOrientation.Landscape : DeviceOrientation.Portrait; } } }
3、注册平台实现
在各个平台项目中实现此接口后,必须通过 DependencyService
注册平台实现,Xamarin.Forms 才可以在运行时找到它们。 通常使用 DependencyAttribute
完成此操作,它指示指定的类型提供接口实现。下面的示例演示如何使用 DependencyAttribute
注册 IDeviceOrientationService
接口的 iOS 实现:
using Xamarin.Forms; [assembly: Dependency(typeof(DependencyServiceDemos.iOS.DeviceOrientationService))] namespace DependencyServiceDemos.iOS { public class DeviceOrientationService : IDeviceOrientationService { public DeviceOrientation GetOrientation() { ... } } }
在此示例中,DependencyAttribute
通过 DependencyService
注册 DeviceOrientationService(参数是 可提供所需接口的具体实现的类型)
。 同样,其他平台上的 IDeviceOrientationService
接口的实现也应通过 DependencyAttribute
注册。有关通过 DependencyService
注册平台实现的详细信息,请参阅 Xamarin.Forms DependencyService 注册和解析。
4、解析平台实现
通过 DependencyService
注册平台实现后,必须先解析实现,才能调用它们。 通常使用 DependencyService.Get<T>
方法在共享代码中完成此操作。
下面的代码示例说明了如何调用 Get<T>
方法解析 IDeviceOrientationService
接口并调用 GetOrientation
方法:
DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();
有关通过 DependencyService
解析平台实现的详细信息,请参阅 Xamarin.Forms DependencyService 注册和解析。
DependencyService 注册和解析
1、注册平台实现
必须通过 DependencyService
注册平台实现,Xamarin.Forms 在运行时才可以找到它们。
可以使用 DependencyAttribute
或 Register
方法执行注册。
注:使用 NET 本机编译的 UWP 项目的版本生成应使用 Register
方法注册平台实现。
通过特性注册在上面说明了,这里说明下Register方法注册:
下面的示例演示如何使用 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,
这样就会在具体类型所实现的接口上注册它。
2、解析平台实现
必须先解析平台实现,然后才能调用它们。 通常使用 DependencyService.Get<T>
方法在共享代码中完成此操作。 不过也可以使用 DependencyService.Resolve<T>
方法完成它。
默认情况下,DependencyService
仅解析具有无参数构造函数的平台实现。 但是,依赖项解析方法可以注入到使用依赖项注入容器或工厂方法的 Xamarin.Forms 中,以解析平台实现。 这种方法可用于解析具有带有参数的构造函数的平台实现。 有关详细信息,请参阅 Xamarin.Forms 中的依赖项解析。
使用Get<T>
默认情况下,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
方法:
DeviceOrientation orientation = DependencyService.Resolve<IDeviceOrientationService>().GetOrientation();
3、管理解析对象的生存期
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方法,该方法执行所需的清除。
从图片库中选选取照片
本文介绍如何创建一种应用程序,使用户可通过该应用程序从手机的图片库中选取照片。 由于 Xamarin.Forms 不包含此功能,因此有必要使用 DependencyService
来访问每个平台上的本机 API。