Xamarin.Forms Registro e resolução de DependencyService
Ao usar a Xamarin.FormsDependencyService
funcionalidade de plataforma nativa para invocar, as implementações de plataforma devem ser registradas com o DependencyService
e, em seguida, resolvidas do código compartilhado para invocá-las.
Registrar as implementações de plataforma
As implementações da plataforma devem ser registradas no DependencyService
para que Xamarin.Forms possam localizá-las em tempo de execução.
O registro pode ser realizado com o DependencyAttribute
, ou com os Register
métodos and RegisterSingleton
.
Importante
Os builds de versão de projetos da UWP que usam a compilação nativa do .NET devem registrar implementações de plataforma com os métodos Register
.
Registro por atributo
O DependencyAttribute
pode ser usado para registrar uma implementação de plataforma com o DependencyService
. O atributo indica que o tipo especificado fornece uma implementação concreta da interface.
O exemplo a seguir usa o DependencyAttribute
para registrar a implementação iOS da IDeviceOrientationService
interface:
using Xamarin.Forms;
[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
public class DeviceOrientationService : IDeviceOrientationService
{
public DeviceOrientation GetOrientation()
{
...
}
}
}
Neste exemplo, o DependencyAttribute
registra o DeviceOrientationService
com o DependencyService
. Isso resulta no tipo concreto que está sendo registrado em relação à interface que ele implementa.
Da mesma forma, as implementações da interface IDeviceOrientationService
em outras plataformas devem ser registradas com o DependencyAttribute
.
Observação
O registro com o DependencyAttribute
é executado no nível do namespace.
Registro por método
Os DependencyService.Register
métodos, e o RegisterSingleton
método, podem ser usados para registrar uma implementação de plataforma com o DependencyService
.
O exemplo a seguir usa o Register
método para registrar a implementação iOS da IDeviceOrientationService
interface:
[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);
}
}
Neste exemplo, o método Register
registra o tipo concreto, DeviceOrientationService
, na interface IDeviceOrientationService
. Como alternativa, uma sobrecarga do método Register
pode ser usada para registrar uma implementação de plataforma com o DependencyService
:
DependencyService.Register<DeviceOrientationService>();
Neste exemplo, o método Register
registra o DeviceOrientationService
com o DependencyService
. Isso resulta no tipo concreto que está sendo registrado em relação à interface que ele implementa.
Como alternativa, uma instância de objeto existente pode ser registrada como um singleton com o RegisterSingleton
método:
var service = new DeviceOrientationService();
DependencyService.RegisterSingleton<IDeviceOrientationService>(service);
Neste exemplo, o RegisterSingleton
método registra a instância do DeviceOrientationService
IDeviceOrientationService
objeto na interface, como um singleton.
Da mesma forma, as implementações da IDeviceOrientationService
interface em outras plataformas podem ser registradas com os Register
métodos ou o RegisterSingleton
método.
Importante
O registro com os Register
métodos and RegisterSingleton
deve ser executado em projetos de plataforma, antes que a funcionalidade fornecida pela implementação da plataforma seja invocada do código compartilhado.
Resolver as implementações da plataforma
As implementações de plataforma devem ser resolvidas antes de serem invocadas. Isso normalmente é feito no código compartilhado, usando o método DependencyService.Get<T>
. No entanto, isso também pode ser realizado com o método DependencyService.Resolve<T>
.
Por padrão, o DependencyService
resolverá somente as implementações de plataforma que têm construtores sem parâmetros. No entanto, um método de resolução de dependência pode ser injetado que Xamarin.Forms usa um contêiner de injeção de dependência ou métodos de fábrica para resolver implementações de plataforma. Essa abordagem pode ser usada para resolver implementações da plataforma que têm construtores com parâmetros. Para obter mais informações, consulte Resolução de dependência no Xamarin.Forms.
Importante
Invocar uma implementação de plataforma que ainda não foi registrada com o DependencyService
resultará na geração de uma NullReferenceException
.
Resolver usando o método Get<T>
O Get<T>
método recupera a implementação da plataforma da interface T
em tempo de execução e:
- Cria uma instância dele como um singleton.
- Retorna uma instância existente como um singleton, que foi registrada com o
DependencyService
método byRegisterSingleton
.
Em ambos os casos, a instância permanecerá durante o tempo de vida do aplicativo e todas as chamadas subsequentes para resolver a mesma implementação de plataforma recuperarão a mesma instância.
O código a seguir mostra um exemplo de chamada ao método Get<T>
para resolver a interface IDeviceOrientationService
e, em seguida, invocação de seu método GetOrientation
:
IDeviceOrientationService service = DependencyService.Get<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();
Como alternativa, esse código pode ser condensado em uma única linha:
DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();
Observação
O Get<T>
método retorna uma instância da implementação da plataforma de interface T
como um singleton, por padrão. No entanto, esse comportamento pode ser alterado. Para obter mais informações, confira Gerenciar o tempo de vida de objetos resolvidos.
Resolver usando o método Resolve<T>
O Resolve<T>
método recupera a implementação da plataforma da interface T
em runtime, usando um método de resolução de dependência que foi injetado com Xamarin.Forms a DependencyResolver
classe. Se um método de resolução de dependência não tiver sido injetado no Xamarin.Forms, o Resolve<T>
método voltará a chamar o Get<T>
método para recuperar a implementação da plataforma. Para obter mais informações sobre como injetar um método de resolução de dependência no Xamarin.Forms, consulte Resolução de dependência no Xamarin.Forms.
O código a seguir mostra um exemplo de chamada ao método Resolve<T>
para resolver a interface IDeviceOrientationService
e, em seguida, invocação de seu método GetOrientation
:
IDeviceOrientationService service = DependencyService.Resolve<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();
Como alternativa, esse código pode ser condensado em uma única linha:
DeviceOrientation orientation = DependencyService.Resolve<IDeviceOrientationService>().GetOrientation();
Observação
Quando o Resolve<T>
método volta a chamar o Get<T>
método, ele retorna uma instância da implementação da plataforma de interface T
como um singleton, por padrão. No entanto, esse comportamento pode ser alterado. Para obter mais informações, confira Gerenciar o tempo de vida de objetos resolvidos.
Gerenciar o tempo de vida de objetos resolvidos
O comportamento padrão da classe DependencyService
é resolver as implementações de plataforma como singletons. Portanto, as implementações de plataforma deverão durar o tempo de vida de um aplicativo.
Esse comportamento é especificado com o argumento opcional DependencyFetchTarget
nos métodos Get<T>
e Resolve<T>
. A enumeração DependencyFetchTarget
define dois membros:
GlobalInstance
, que retorna a implementação de plataforma como um singleton.NewInstance
, que retorna uma nova instância da implementação de plataforma. O aplicativo, então, é responsável por gerenciar o tempo de vida da instância de implementação de plataforma.
Os métodos Get<T>
e Resolve<T>
definem seus argumentos opcionais como DependencyFetchTarget.GlobalInstance
e, portanto, as implementações de plataforma são sempre resolvidas como singletons. Esse comportamento pode ser alterado para que novas instâncias de implementações de plataforma sejam criadas por meio da especificação de DependencyFetchTarget.NewInstance
como argumentos para os métodos Get<T>
e Resolve<T>
:
ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
Neste exemplo, o DependencyService
cria uma nova instância da implementação de plataforma para a interface ITextToSpeechService
. Todas as chamadas subsequentes para resolver o ITextToSpeechService
também criarão novas instâncias.
A consequência de sempre criar uma nova instância de uma implementação de plataforma é que o aplicativo se torna responsável por gerenciar o tempo de vida das instâncias. Isso significa que, se você assinar um evento definido em uma implementação de plataforma, deverá cancelar o evento quando a implementação de plataforma não for mais necessária. Além disso, isso significa que talvez seja necessário que as implementações de plataforma implementem IDisposable
e limpem seus recursos em métodos Dispose
. O aplicativo de exemplo demonstra esse cenário em suas implementações de plataforma TextToSpeechService
.
Quando um aplicativo terminar de usar uma implementação de plataforma que implementa IDisposable
, ele deverá chamar a implementação Dispose
do objeto. Uma maneira de realizar isso é com uma instrução using
:
ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
using (service as IDisposable)
{
await service.SpeakAsync("Hello world");
}
Neste exemplo, depois que o método SpeakAsync
é invocado, a instrução using
automaticamente descarta o objeto de implementação de plataforma. Isso resulta no método Dispose
do objeto que está sendo invocado, que executa a limpeza necessária.
Para obter mais informações sobre como chamar o método Dispose
de um objeto, veja Como usar objetos que implementam IDisposable.