Xamarin.Forms Registro e resolução do DependencyService

Baixar exemplo Baixar o exemplo

Ao usar o Xamarin.FormsDependencyService para invocar a funcionalidade de plataforma nativa, as implementações de plataforma devem ser registradas com o DependencyServicee, em seguida, resolvidas do código compartilhado para invocá-las.

Registrar as implementações de plataforma

As implementações de plataforma devem ser registradas com o DependencyService para que Xamarin.Forms possam localizá-las em runtime.

O registro pode ser executado com os DependencyAttributemétodos , ou e RegisterSingletonRegister .

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 do 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 do 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 objeto na IDeviceOrientationService 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 e 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 em Xamarin.Forms que usa um contêiner de injeção de dependência ou métodos de fábrica para resolve 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 de plataforma da interface T em runtime e:

  • Cria uma instância dela como um singleton.
  • Retorna uma instância existente como um singleton, que foi registrado com o DependencyService pelo RegisterSingleton método .

Em ambos os casos, a instância viverá durante o tempo de vida do aplicativo e todas as chamadas subsequentes para resolve 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 de plataforma da 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 de plataforma da interface T em runtime, usando um método de resolução de dependência que foi injetado Xamarin.Forms com 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 fará fallback para 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 de plataforma da 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.