Registro y resolución de DependencyService de Xamarin.Forms

Descargar ejemploDescargar el ejemplo

Al usar para invocar la Xamarin.FormsDependencyService funcionalidad de plataforma nativa, las implementaciones de plataforma deben registrarse con DependencyServicey, a continuación, resolverse desde código compartido para invocarlas.

Registro de las implementaciones de la plataforma

Las implementaciones de la plataforma deben estar registradas con DependencyService para que Xamarin.Forms pueda localizarlas en tiempo de ejecución.

El registro se puede realizar con DependencyAttribute o con los métodos Register y RegisterSingleton.

Importante

Las compilaciones de versión de los proyectos de UWP que usan la compilación nativa de .NET deben registrar las implementaciones de plataforma con los métodos Register.

Registro por atributo

DependencyAttribute se puede usar para registrar una implementación de la plataforma con DependencyService. El atributo indica que el tipo especificado proporciona una implementación concreta de la interfaz.

En el siguiente ejemplo se usa DependencyAttribute para registrar la implementación de iOS de la interfaz IDeviceOrientationService:

using Xamarin.Forms;

[assembly: Dependency(typeof(DeviceOrientationService))]
namespace DependencyServiceDemos.iOS
{
    public class DeviceOrientationService : IDeviceOrientationService
    {
        public DeviceOrientation GetOrientation()
        {
            ...
        }
    }
}

En este ejemplo, DependencyAttribute registra DeviceOrientationService con DependencyService. Esto da como resultado el tipo concreto que se va a registrar en la interfaz que implementará.

De forma similar, las implementaciones de la interfaz de IDeviceOrientationService en otras plataformas se debe registrar con DependencyAttribute.

Nota

El registro con DependencyAttribute se realiza en el nivel de espacio de nombres.

Registro por método

Los métodos DependencyService.Register, y el método RegisterSingleton, se pueden usar para registrar una implementación de la plataforma con DependencyService.

En el siguiente ejemplo se usa el método Register para registrar la implementación de iOS de la interfaz IDeviceOrientationService:

[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);
    }
}

En este ejemplo, el método Register registra el tipo concreto, DeviceOrientationService, en la interfaz de IDeviceOrientationService. De forma alternativa, se puede usar una sobrecarga del método Register para registrar una implementación de plataforma con DependencyService:

DependencyService.Register<DeviceOrientationService>();

En este ejemplo, el método Register registra DeviceOrientationService con DependencyService. Esto da como resultado el tipo concreto que se va a registrar en la interfaz que implementará.

Como alternativa, se puede registrar una instancia de objeto existente como singleton con el método RegisterSingleton:

var service = new DeviceOrientationService();
DependencyService.RegisterSingleton<IDeviceOrientationService>(service);

En este ejemplo, el método RegisterSingleton registra la instancia del objeto DeviceOrientationService en la interfaz IDeviceOrientationService, como singleton.

De forma similar, las implementaciones de la interfaz IDeviceOrientationService en otras plataformas se puede registrar con los métodos Register, o el método RegisterSingleton.

Importante

El registro con los métodos Register y RegisterSingleton se debe realizar en los proyectos de la plataforma antes de que se invoque la funcionalidad que ha proporcionado la implementación de la plataforma mediante el código compartido.

Resolución de las implementaciones de la plataforma

Las implementaciones de la plataforma deben resolverse antes de invocarse. Normalmente, esto se realiza en código compartido mediante el método DependencyService.Get<T>. Sin embargo, también se puede lograr con el método DependencyService.Resolve<T>.

De forma predeterminada, DependencyService solo resuelve implementaciones de plataforma con constructores sin parámetros. Aun así, se puede incorporar a Xamarin.Forms un método de resolución de dependencias que use un contenedor de inserción de dependencias o métodos de generador para resolver implementaciones de plataforma. Este enfoque puede usarse para resolver las implementaciones de plataforma que tienen constructores con parámetros. Para obtener más información, vea Inserción de dependencias en Xamarin.Forms.

Importante

La invocación de una implementación de la plataforma que no se haya registrado con DependencyService tendrá como resultado la generación de NullReferenceException.

Resolución mediante el método Get<T>

El método Get<T> recupera la implementación de la plataforma de la interfaz de T en tiempo de ejecución y luego hace una de estas acciones:

  • Crea una instancia de ella como singleton.
  • Devuelve una instancia existente como singleton, que se registró con DependencyService por el método RegisterSingleton.

En ambos casos, esta instancia estará activa durante la vigencia de la aplicación, y las llamadas subsiguientes para resolver la misma implementación de la plataforma recuperarán la misma instancia.

En el código siguiente, se muestra un ejemplo de llamada al método Get<T> para resolver la interfaz de IDeviceOrientationService y, después, invocar su método GetOrientation:

IDeviceOrientationService service = DependencyService.Get<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();

Como alternativa, este código se puede comprimir en una sola línea:

DeviceOrientation orientation = DependencyService.Get<IDeviceOrientationService>().GetOrientation();

Nota

El método Get<T> devuelve una instancia de la implementación de la plataforma de la interfaz de T como singleton de forma predeterminada. No obstante, se puede modificar este comportamiento. Para obtener más información, vea Administración de la vigencia de los objetos resueltos.

Resolución mediante el método Resolve<T>

El método Resolve<T> recupera la implementación de la plataforma de la interfaz de T en tiempo de ejecución mediante un método de resolución de dependencias que se ha insertado en Xamarin.Forms con la clase DependencyResolver. Si un método de resolución de dependencias no se ha insertado en Xamarin.Forms, el método Resolve<T> llamará al método Get<T> como solución alternativa para recuperar la implementación de la plataforma. Para obtener más información sobre la inserción de métodos de resolución de dependencias en Xamarin.Forms, vea Resolución de dependencias en Xamarin.Forms.

En el código siguiente, se muestra un ejemplo de llamada al método Resolve<T> para resolver la interfaz de IDeviceOrientationService y, después, invocar su método GetOrientation:

IDeviceOrientationService service = DependencyService.Resolve<IDeviceOrientationService>();
DeviceOrientation orientation = service.GetOrientation();

Como alternativa, este código se puede comprimir en una sola línea:

DeviceOrientation orientation = DependencyService.Resolve<IDeviceOrientationService>().GetOrientation();

Nota

Cuando el método Resolve<T> llama al método Get<T> como solución alternativa, devuelve una instancia de la implementación de la plataforma de la interfaz de T como singleton de forma predeterminada. No obstante, se puede modificar este comportamiento. Para obtener más información, vea Administración de la vigencia de los objetos resueltos.

Administración de la vigencia de los objetos resueltos

El comportamiento predeterminado de la clase DependencyService es resolver las implementaciones de la plataforma como elementos singleton. Por lo tanto, las implementaciones de la plataforma permanecerán activas durante la vigencia de la aplicación en cuestión.

Este comportamiento se especifica con el argumento opcional DependencyFetchTarget en los métodos Get<T> y Resolve<T>. La enumeración DependencyFetchTarget define dos miembros:

  • GlobalInstance, que devuelve la implementación de la plataforma como singleton.
  • NewInstance, que devuelve una nueva instancia de la implementación de la plataforma. La aplicación es responsable de administrar la vigencia de la instancia de la implementación de la plataforma.

Los métodos Get<T> y Resolve<T> establecen sus argumentos opcionales en DependencyFetchTarget.GlobalInstance, por lo que las implementaciones de la plataforma siempre se resuelven como elementos singleton. Este comportamiento se puede cambiar especificando DependencyFetchTarget.NewInstance como argumentos para los métodos Get<T> y Resolve<T> con el fin de que crear las instancias de las implementaciones de la plataforma:

ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);

En este ejemplo, DependencyService crea una instancia de la implementación de la plataforma para la interfaz de ITextToSpeechService. Las llamadas subsiguientes para resolver ITextToSpeechService también crearán nuevas instancias.

La consecuencia de crear siempre una nueva instancia de una implementación de la plataforma es que la aplicación adquiere la responsabilidad de administrar la vigencia de las instancias. Esto significa que, si se suscribe a un evento definido en una implementación de la plataforma, deberá cancelar la suscripción al evento cuando ya no se requiera la implementación de la plataforma. Además, significa que puede ser necesario que las implementaciones de la plataforma implementen IDisposable y realicen una limpieza de sus recursos en los métodos Dispose. La aplicación de ejemplo muestra este escenario en sus implementaciones de la plataforma de TextToSpeechService.

Cuando una aplicación termina de utilizar una implementación de la plataforma que implementa IDisposable, debe llamar a la implementación del objeto Dispose. Una manera de realizar esta acción es usar una instrucción using:

ITextToSpeechService service = DependencyService.Get<ITextToSpeechService>(DependencyFetchTarget.NewInstance);
using (service as IDisposable)
{
    await service.SpeakAsync("Hello world");
}

En este ejemplo, una vez que se ha invocado el método SpeakAsync, la instrucción using desecha automáticamente el objeto de la implementación de la plataforma. Esto da como resultado la invocación del método Dispose del objeto, que realiza la limpieza requerida.

Para obtener más información sobre cómo llamar al método Dispose de un objeto, vea Uso de objetos que implementan IDisposable.