[HANGOUT WPSUG] Azure Mobile Services y Microsoft AppInsights

Logo-256_png-160x0

Hola a todos!

Hoy tenemos a dos grandes de la comunidad invitados al hangout mensual de WPSUG.

Hablo de Quique Martinez (Windows Azure MVP) y Rafael Serna (Nokia Developer Champion).

Como podréis adivinar, el hangout de hoy estará dedicado a la nube. En concreto, Rafa nos hablará de Azure Mobile Services y Quique de Microsoft Application Insights, una nueva tecnología, actualmente en preview, para monitorizar nuestras aplicaciones móviles (Windows Store y Windows Phone) y nuestros servicios.

¿Cuando?

Hoy jueves 20 a las 19:00 (GMT+1)

¿Donde?

En YouTube, en la siguiente dirección: http://www.youtube.com/watch?v=ut3Ykb3mQD0

Os esperamos!!

Recordad también que podéis acceder a nuestro canal de YouTube para poder ver los videos de los hangouts anteriores.

Un saludo y Happy Coding!!

[Windows 8.1] Listas paginadas

Hola a todos!

Hoy vamos a cambiar un poco de temática, para hablar de paginación en apps Windows Store para Windows 8.1.

En Windows Phone 8, usamos la capacidad del LongListSelector para detectar el final de la lista y poder lanzar la carga de más elementos. En Windows Store no disponemos de LongListSelector. En su lugar usamos un control GridView o ListView. Estos controles no tienen la capacidad de detectar la compresión final para cargar más elementos. En su lugar, realizan la carga de más páginas automáticamente usando la interface ISupportIncrementalLoading.

Esta interface debe estar implementada en la colección que enlazamos al GridView o ListView. Por defecto no existe ninguna colección que la implemente por lo que tendremos que crearnos la nuestra propia. Para ello podemos partir de una ObservableCollection. ISupportIncrementalLoading implementa una propiedad de solo lectura llamada HasMoreItems y un método llamado LoadMoreItemsAsync:

ISupportIncrementalLoading
public class PaginatedCollection<T> : ObservableCollection<T>, ISupportIncrementalLoading
{

    public bool HasMoreItems
    {
        get { throw new NotImplementedException(); }
    }

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        throw new NotImplementedException();
    }
}

Normalmente necesitaremos usar este tipo de colección con más de un tipo de dato y la carga de más páginas, en el método LoadMoreItemsAsync, también variará. Para solventar esto podemos usar una táctica parecida a la empleada en el DelegateCommand en MVVM. Vamos a añadir un constructor que se encargue de recibir dos Func<T>: Uno para saber si debemos cargar más elementos y otro para cargarlos:

PaginatedCollection ctor
Func<uint, IEnumerable<T>> getMoreItems;
Func<bool> getHasMoreItems;

public PaginatedCollection(Func<uint, IEnumerable<T>> _getMoreItems, Func<bool> _getHasMoreItems)
{
    getMoreItems = _getMoreItems;
    getHasMoreItems = _getHasMoreItems;
}

Ahora simplemente, la propiedad HasMoreItems llamará a getHasMoreItems:

HasMoreItems
public bool HasMoreItems
{
    get
    {
        return getHasMoreItems();
    }
}

En el método LoadMoreItemsAsync, tendremos que trabajar un poco más. Básicamente debemos realizar los siguientes pasos:

  1. Llamar a getMoreItems
  2. Insertar los elementos nuevos en la colección base
  3. Devolver un nuevo LoadMoreItemsResult con el conteo de elementos recibidos.

Pero existen ciertas peculiaridades. El método LoadMoreItemsAsync devuelve un tipo IAsyncOperation<LoadMoreItemsResul>. Tendremos que ejecutar nuestro código en una Task para luego convertirlo a IAsyncOperation. Pero al ejecutar el código en una Task, si intentamos añadir elementos a la colección base obtendremos una excepción cross thread. Para evitar esta excepción, antes de modificar el método LoadMoreItemsAsync, vamos a añadir una propiedad pública y estática a nuestra clase App, para poder exponer el Frame de la aplicación y acceder fácilmente al Dispatcher que contiene, de forma que podamos usar el hilo principal de UI para añadir elementos a la colección. ¿Porqué? Pues por que la base de nuestra colección es una ObservableCollection, que notifica a la UI cada vez que su contenido cambia (al añadir o eliminar un elemento) y esta notificación debe producirse desde el hilo principal de interface de usuario:

Static RootFrame
sealed partial class App : Application
{
    public static Frame RootFrame { get; set; }

Una vez hecho esto, ya podemos escribir el código del método LoadMoreItemsAsync:

LoadMoreItemsAsync
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
    return Task.Run<LoadMoreItemsResult>(async () =>
    {
        var newItems = getMoreItems(count);

        await App.RootFrame.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
        () =>
        {
            foreach (var item in newItems)
                base.Add(item);
        });

        return new LoadMoreItemsResult() { Count = (uint)newItems.Count() };
    }).AsAsyncOperation<LoadMoreItemsResult>();
}

En este código, lo primero que hacemos es devolver una ejecución de una Task, como una AsyncOperation de LoadMoreItemsResult. Internamente dentro de esta Task, llamamos al Func<uint, IEnumerable<T>> que recibimos en el constructor, getMoreItems, pasándole el conteo de elementos que nos pide la interface de usuario. Esto puede ser muy útil si nuestra petición de nuevos datos permite indicar cuantos elementos obtener.

Una vez que recibimos los elementos, usamos el método RunAsync del dispatcher incluido en el RootFrame para, mediante un foreach, añadir cada elemento devuelto a la colección base. Por último la tarea devuelve un nuevo LoadMoreItemsResult, con el número de elementos devueltos.

Ya tenemos el código de nuestra clase PaginatedCollection<T> terminado. Ahora llega el momento de usarla en una ViewModel. En primer lugar creamos una variable privada y una propiedad pública, como con cualquier otra lista:

Public property use
private PaginatedCollection<string> collection;
public PaginatedCollection<string> Collection
{
    get { return collection; }
    set
    {
        collection = value;
        RaisePropertyChanged();
    }
}

A continuación vamos a escribir dos métodos privados, uno para devolver true/false y otro para obtener nuevos elementos. Deben coincidir con la firma que hemos declarado en la colección: Func<bool> y Func<uint, IEnumerable<T>> respectivamente:

HasMoreItems & GetMoreItems
private bool HasMoreItem()
{
    if (elementCount > 100)
        return false;

    return true;
}

private IEnumerable<string> GetMoreItems(uint count)
{
    IList<string> list = new List<string>();

    for (int i = 0; i < count; i++)
    {
        list.Add(string.Format(«string number {0}», i));
    }
    elementCount += count;

    return list;
}

En este ejemplo, para no complicarlo, no estamos llamando a ningún servicio, simplemente cada vez que se nos piden datos, creamos nuevas strings. Exactamente el número que nos pide la lista. mientras ese número esté por debajo de 100, seguimos devolviendo true en nuestro método boolean. Por último, en nuestro constructor, inicializamos la nueva colección:

Collection constructor
public MainViewModel()
{
    collection = new PaginatedCollection<string>(GetMoreItems, HasMoreItem);
}

Y ahora solo nos queda el XAML. Para este ejemplo usaremos un GridView. También podríamos usar un ListView, que soporta paginación.

GridView XAML
<GridView ItemsSource=»{Binding Collection}«
            IncrementalLoadingThreshold=«1»
            IncrementalLoadingTrigger=«Edge»>
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid Margin=«24» Width=«350»>
                <TextBlock Text=»{Binding}« FontSize=«36»/>
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

Como podemos ver no existe nada especial en esta declaración del GridView, salvo dos propiedades: IncrementalLoadingThreshold e IncrementalLoadingTrigger. Por defecto IncrementalLoadingTrigger tiene el valor Edge, la he indicado explícitamente para mostrarla, pero no es necesario hacerlo. IncrementalLoadingThreshold es muy importante sin embargo. Indica el número de páginas pendientes de ver antes de pedir nuevas. Cuidado, el número de páginas. Si introducimos un valor de 1, la petición de nuevos datos no se realizará hasta que el usuario no llegue casi al final de la lista. si introducimos 10, dejaremos mucho espacio entre el final y el usuario. Debemos calibrar esta propiedad bien, para equilibrar la respuesta al usuario con el uso de recursos.

Y ya tenemos terminado nuestro código. Si ejecutamos, veremos que funciona perfectamente. Ahora, una pregunta para nota. ¿Donde se realiza la carga inicial de datos? En ningún momento hemos llamado para obtener datos inicialmente. Esta es una de las ventajas del sistema de paginación. No tenemos que realizar la carga inicial. Cuando el control se enlaza, ve que tiene 0 elementos y como está dentro del Threshold indicado, pide datos a la lista inmediatamente. Con lo que nos hemos ahorrado tener que inicializarla nosotros mismos.

Con esto llegamos al final de este artículo. Espero que os haya gustado y sea útil. Como siempre, aquí tenéis el código de ejemplo en funcionamiento para que podáis jugar con él y tenerlo de referencia.

Un saludo y Happy Coding!!

[Windows Phone 8] Ejecución de código en segundo plano (III y Fin)

Hola a todos! Vamos a por el tercer artículo sobre ejecución de código en Background.

Volvemos a la carga, tras ver como realizar geolocalización en background y como ejecutar tareas programadas en background. En esta ocasión vamos a descubrir como reproducir música independientemente de nuestra app, de forma que si el usuario la cierra, la música siga reproduciéndose. Podemos ver ejemplos de apps que usan reproducción de audio en segundo plano, tales como Nokia MixRadio, P|Cast, Spotify y muchas otras.

Existen dos tipos de agentes de audio diferentes: El agente de reproducción de audio y el agente de streaming de audio. Su uso es exactamente el mismo. Su principal diferencia es la forma en la que entregan el audio al sistema. El agente de audio simplemente obtiene una Uri (local o remota) y la pasa al sistema de reproducción. El agente de streaming de audio debe implementar su propia clase de decodificación de audio (MediaStreamSource) encargada de decodificar el audio y pasárselo al sistema. Esto último nos permite una gran libertad a la hora de trabajar con audio, pero requiere un esfuerzo y conocimientos sobre audio y codecs extra, pues seremos los encargados de su creación de principio a fin.

En general, todo audio que se reproduce en Windows Phone, sigue la siguiente estructura:

image

En el gráfico anterior podemos separar tres partes, representadas por colores.

Las cajas grises indican partes del sistema. Entre ellas encontramos el reproductor en background del sistema, la cola de multimedia de Zune (si, Zune sigue vivo en lo más profundo de vuestros Windows Phone, aunque desde Microsoft se esfuercen en borrar su nombre de la historia…) y el control de volumen universal.

Las cajas naranjas indican las partes que debemos implementar para crear una aplicación capaz de reproducir audio en background. Simplemente tenemos la aplicación en si misma y el agente de audio.

Por último, las cajas verdes simbolizan el código que tendremos que añadir para usar un agente de streaming de audio.

Como podemos ver en el gráfico, la parte común entre ambos sistemas es que siempre tenemos que crear un agente de audio, por lo que nos centraremos en él en este artículo. Si quieres información más profunda sobre el streaming de audio, empieza tu viaje por la madriguera de conejo aquí. Suerte con la pastilla roja.

Después de haber visto las tareas programadas, esto os va a “sonar” mucho. De echo, la mecánica es la misma. tendremos un proyecto para la reproducción en background, un agente, que se integrará con nuestra aplicación y con los controles de audio del sistema. De esta forma, desde nuestra app podremos indicarle que reproducir y cuando empezar, parar o cambiar de una canción a otra. Pero al mismo tiempo, el usuario podrá abandonar nuestro programa y usar los controles de audio (reproducir, pausar, adelante y atrás) integrados en el sistema para gestionar el audio. Cada vez que el usuario realice una acción en estos controles, se invocará un método OnUserAction en nuestro agente. De la misma forma, cada vez que el estado de reproducción cambie, se invocará un método OnPlayStateChanged, por ejemplo cuando acabe una canción, para que podamos reproducir la siguiente.

Como la ejecución es bajo demanda, es decir, es el usuario o el audio quienes marcan cuando se ejecutarán estos métodos, no tenemos intervalos prefijados como en el agente de tareas programadas. Pero eso no nos libra de tener restricciones:

  • Memoria: tendremos un límite de consumo. Hasta Windows Phone 8 GDR3, este límite es de 20Mb. Con GDR3 el límite sube a los 25Mb. Es importante tener en cuenta también que, con un agente en streaming, compartiremos esa memoria con el agente de audio. no tendremos 20/25Mb para cada uno.
  • Tiempo: Aunque la ejecución se realiza bajo demanda, tendremos que llamar a NotifyComplete o Abort antes de pasar 30 segundos o se cerrará el agente.

Ahora que ya conocemos toda la teoría necesaria, vamos a ver un ejemplo práctico de reproducción de audio en segundo plano. Lo primero que vamos a hacer es crear una nueva solución, con un proyecto Blank Application y un proyecto “Windows Phone Audio Playback agent”. Por defecto nos creará una clase llamada AudioAgent.cs que hereda de AudioPlayerAgent y sobre escribe una serie de métodos:

  • OnPlayStateChanged
  • OnUserAction
  • OnError

Por defecto veremos que el método OnUserAction ya tiene una lógica básica implementada, con un Switch() case que se encarga de parar, reproducir, saltar canción, rebobinar, avanzar…

OnUserAction
protected override void OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param)
{
    switch (action)
    {
        case UserAction.Play:
            if (player.PlayerState != PlayState.Playing)
            {
                player.Play();
            }
            break;
        case UserAction.Stop:
            player.Stop();
            break;
        case UserAction.Pause:
            player.Pause();
            break;
        case UserAction.FastForward:
            player.FastForward();
            break;
        case UserAction.Rewind:
            player.Rewind();
            break;
        case UserAction.Seek:
            player.Position = (TimeSpan)param;
            break;
        case UserAction.SkipNext:
            player.Track = GetNextTrack();
            break;
        case UserAction.SkipPrevious:
            AudioTrack previousTrack = GetPreviousTrack();
            if (previousTrack != null)
            {
                player.Track = previousTrack;
            }
            break;
    }

    NotifyComplete();
}

También tiene dos métodos ya creados: GetPreviousTrack y GetNextTrack. Estos métodos son llamados desde OnUserAction y OnPlayStateChanged. Para hacer un reproductor básico, solo deberíamos incluir código en estos dos métodos finales para obtener la canción anterior y siguiente respectivamente.

Lo primero que vamos a hacer en la clase AudioAgent es crearnos una lista estática de AudioTracks, para este ejemplo voy a usar la url de los MP3 del podcast WPControla que hice con Rafa Serna hace un tiempo:

AudioTrack list
private static IList<AudioTrack> tracks = new List<AudioTrack>
{
    new AudioTrack
    {
        Source = new Uri(«http://audios.wpcontrola.com/capitulo1.mp3»),
        Title = «WPControla 1»,
        Artist = «Rafa y Yeray»,
        Album = «WPControla greatest hits»
    },
    new AudioTrack
    {
        Source = new Uri(«http://audios.wpcontrola.com/capitulo2.mp3»),
        Title = «Captulo 2»,
        Artist = «Rafa y Yeray»,
        Album = «WPControla greatest hits»
    },

};

Por supuesto en una aplicación real tendrías un servicio que fuese el encargado de devolverte la lista de canciones, no las tendrías codificadas en el agente de audio. Pero lo que si es recomendable es que tengas una lista estática, pues así esta no se crearía y destruiría con las diferentes invocaciones del control del sistema.

También necesitaremos un entero que nos permita seguir el índice de la lista que se está reproduciendo en cada momento.

Una vez que tenemos nuestra lista creada, vamos a añadir el código necesario a los métodos GetPreviousTrack y GetNextTrack:

GetPreviousTrack/GetNextTrack
private AudioTrack GetNextTrack()
{
    if (++currentTrackNumber >= tracks.Count)
    {
        currentTrackNumber = 0;
    }

    return tracks[currentTrackNumber];
}

private AudioTrack GetPreviousTrack()
{
    if (currentTrackNumber < 0)
    {
        currentTrackNumber = tracks.Count 1;
    }

    return tracks[currentTrackNumber];
}

Simplemente nos movemos por la lista, devolviendo la track que corresponda en cada caso. Por último para terminar con el código de nuestro agente, solo nos queda controlar la acción Play en el método OnUserAction. Si la track del reproductor no está establecida, la establecemos nosotros:

Acción Play
case UserAction.Play:
    if (player.PlayerState != PlayState.Playing)
    {
        if (player.Track == null)
            player.Track = tracks[currentTrackNumber];
        player.Play();
    }
    break;

Y ahora ya podemos ir a nuestra aplicación. Este ejemplo es muy simple. Tendremos un botón “play” con el que comenzar la reproducción de nuestros tracks en segundo plano. Para ello usaremos la clase BackgroundAudioPlayer, que contiene la instancia global del reproductor del sistema:

PlayAudio command execution
private void PlayAudioExecute()
{
    if (BackgroundAudioPlayer.Instance.PlayerState != PlayState.Playing)
        BackgroundAudioPlayer.Instance.Play();
    else
        BackgroundAudioPlayer.Instance.Pause();
}

Y Voila! Ya tenemos nuestro reproductor del Podcast de WPControla integrado con el sistema!

Si ejecutamos la aplicación y presionamos el botón “play”, empezaremos a escuchar el capítulo 1 de WPControla. Podemos volver a la pantalla de inicio del sistema y presionar la tecla de volumen para ver que se muestra la información de cada track y responde a nuestras ordenes.

NOTA: Para que todo funcione, pruébalo en un dispositivo real, en los emuladores tiene un comportamiento errático que lo hace fallar a veces.

Y con esto llegamos al final de esta serie dedicada a la ejecución de código en segundo plano. Como siempre, aquí tienes el código listo para descarga, de forma que tengas un punto de partida, con MVVM y bien colocado.

Un saludo y Happy Coding!!

P.D.: Si quieres escuchar todos los capítulos de WPControla, puedes hacerlo aquí!

[WPSUG] Materiales de Nokia MixRadio API

Hola a todos!

El pasado jueves 30 de enero de 2014 tuvimos un nuevo hangout de WPSUG, en esta ocasión sobre APIs de música que podemos integrar en nuestras aplicaciones Windows Phone y Windows Store.

Javier Suarez nos habló de XBox music y yo me centré en Nokia MixRadio. A continuación tenéis el enlace al vídeo del Hangout en nuestro canal de YouTube, las slides que usé sobre Nokia MixRadio y el ejemplo completo que enseñé. Espero que os sea de utilidad.

Video de Youtube WPSUG: APIs de Música

Slides de mi parte sobre Nokia MixRadio en SlideShare:

Y por último, el código fuente del ejemplo, que podéis descargar aquí.

Un saludo y Happy Coding!!