Cómo descargar imágenes de internet (Para Android y WinRT)

Hoy me he encontrado con un problema que a priori suena bastante tonto y trivial, pero que investigando como abordarlo, te das cuenta de que si no tienes las cosas muy claras o mucha soltura con el tema Streams, te puedes perder fácilmente.

El problema concreto es, dada una URL que apunta a un fichero de imagen, descargar, desde un dispositivo móvil dicha imagen para mostrársela al usuario en el canvas de la aplicación. La idea básica es simple; consiste en “abrir” la imagen en memoria como un stream o un array de bytes, copiar dicho stream/array en memoria, generar un objeto bitmap y asignárselo a algún control o widget que tengamos en nuestra aplicación.

Aquí os dejo el código de como hacerlo tanto en Android como en WinRT/Metro

Para Android:


// Use an AsyncTask, network operations in UI thread are not allowed in Android 3.0+
private class DecodeImage extends AsyncTask<String, Integer, Void> {

    Bitmap bm;

    @Override
    protected Void doInBackground(String... params) {
    	URL url;
        try {
            url = new URL(params[0]);
            bm = BitmapFactory.decodeStream(url.openStream());
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
    	imageView.setImageBitmap(bm);
    }

}

Para WinRT:


System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();

...

System.Net.Http.HttpResponseMessage imageResponse = await client.GetAsync(imageUrl);

// A memory stream where write the image data
Windows.Storage.Streams.InMemoryRandomAccessStream randomAccess =
	new Windows.Storage.Streams.InMemoryRandomAccessStream();

Windows.Storage.Streams.DataWriter writer = 
	new Windows.Storage.Streams.DataWriter(randomAccess.GetOutputStreamAt(0));

// Write and save the data into the stream
writer.WriteBytes(await imageResponse.Content.ReadAsByteArrayAsync());
await writer.StoreAsync();

// Create a Bitmap and assign it to the target Image control
Windows.UI.Xaml.Media.Imaging.BitmapImage bm =
	new Windows.UI.Xaml.Media.Imaging.BitmapImage();
await bm.SetSourceAsync(randomAccess);
imageControl.Source = bm;

Posted in Android, C#, Java, Windows 8 | Tagged , , , | Leave a comment

Cantidad != Calidad

En los últimos días he estado mirando en detalle las posibilidades de Google Play Store en cuanto a aplicaciones de calidad. Cuando busco una nueva aplicación para mi móvil espero que dicha aplicación le aporte cierto valor al cacharro, una característica que o bien potencie las propias del dispositivo, o bien le agregue una con la que no contase anteriormente; es decir, busco una aplicación de calidad, una que merezca la pena tener instalada en mi móvil y que me haga usar el mismo de una forma diferente para poder hacer algo que antes no podía, quiero que la App me de un valor agregado más que el mero hecho de hacer lo que tiene que hacer.

La app de PayPal para Windows Phone 8

La pregunta es, ¿Se da esto en la Google Play Store para dispositivos Android? La respuesta es que no, al menos no mayormente. La inmensa mayoría de las aplicaciones gratuitas de la “AppStore” de Google son idioteces inútiles, sin ninguna función más allá de reproducir algún sonido pregrabado al pulsar un botón, hacer burla y mofa de algún personaje famosete, o simplemente, aprovechar la ignorancia del usuario asegurando que el programa hará “algo” aparentemente complicado y/o útil, cuando realmente dicho programa no es más que una pantalla que simula “no funcionar” mientras te muestra banners de publicidad (Esto de la publicidad en el móvil daría para un debate muy muy muy largo).

Historia a parte son los clientes oficiales de las distintas redes sociales que deben casi obligatoriamente tener presencia oficial en los crecientes en cantidad dispositivos móviles, estoy hablando de Facebook, Twitter, Instagram, etcétera. Por lo general, y al tener como fuente de ingresos asuntos distintos de los teléfonos móviles, estas mega-empresas pueden ofrecer aplicaciones de calidad, gratuitamente y sin publicidad, puesto que ya se financian por otras vías y han de captar cuantos más clientes mejor.

Un poco más de dedicación no hace daño…

Lo primero que salta a la vista en el caso de la mayor parte de las aplicaciones gratuitas en la Play Store es que sus creadores no se esmeran mucho a la hora de crear una de las partes más importantes de estos programas como lo es la UI o interfaz de usuario. Algunos se limitan sencillamente a colocar botones al tuntún sin un poco de esmero y sin usar los temas nativos del sistema.

Una aplicación gratuita de Google Play muy descargada

Yo creo que a la hora de crear una App móvil, la importancia del diseño de la UI es capital, y se debería diseñar con mucho cuidado y aprovechando las capacidades nativas del sistema. Esto puede conseguirse sin ningún drama siguiendo los consejos que hay en la página de diseño de la web de desarrollo de Android. Esto se cumple a rajatabla en los desarrollos para las dos plataformas rivales del androide verde: iOS y Windows Phone 8. Esto se resulta de que si un desarrollador quiere ver su aplicación en las tiendas de estos sistemas, antes debe superar una batería de pruebas automatizadas y humanas que darán o no el visto bueno a la aplicación, donde el diseño de la UI y la integración con el sistema suman muchos puntos (De hecho, en algunos casos no ceñirse a las reglas de diseño es suficiente para que rechacen una aplicación sin más pruebas ni testeos).

Por la contra, la aprobación de aplicaciones para Android parece no contar con un sistema de prueba y testeo pormenorizado, lo que resulta en una subida más rápida de la aplicación, a cambio de no filtar las toneladas de mierda inútil que la gente ociosa sube a la tienda.

La montaña de mierda, aunque montaña, sigue siendo mierda

Es por esto, entre otras cosas, por lo que no hay que tomar muy en serio a los fans del robotito verde que se vanaglorian en que pueden elegir entre una mayor oferta de aplicaciones, pues las más “importantes” y que usa el 90% de la gente existen para las 3 plataformas mencionadas, y el resto suelen ser aplicaciones de poca monta que como ya he dicho no aportan un valor agregado al Smartphone. ¿Qué gracia tiene una aplicación que reproduce las mejores frases de Anotnio Recio? ¿Cuál es la utilidad real de una aplicación que supuestamente recupera la clave de wifis protegidas y que en realidad solo recupera las claves de fábrica (y que casi nunca funcionan)?

Estoy firmemente convencido de que una aplicación para iOS o para Windows Phone (que no sea una de esas “indispensables”) vale por 5 aplicaciones para Android, pues como ya he dicho, se requiere un mayor trabajo y mimo a la hora de diseñar e implementar el programa si de verdad uno quiere verlo en los escaparates de estos sistemas, lo que acaba repercutiendo directamente en la calidad de las aplicaciones tanto a nivel de UI como de funcionamiento.

La app oficial de ebay para iOS

Por lo que, al final, lo que realmente importa son las aplicaciones de calidad, las que hacen de tu Smartphone un aparato polivalente y con nuevas o mejoradas capacidades. Porque por eso se les llama teléfonos inteligentes, por ponerte en la palma de la mano capacidades útiles e interesantes, y no una retahíla de sonidos pregrabados y anuncios a troche y moche, que para eso ya está Antena 3.

Posted in Android, opinión, Windows Phone | Leave a comment

SportTracker: Accediendo a la cámara en Windows Phone 8

Hace poco he comenzado a hacer una aplicación móviles para sistemas Windows Phone 8. Después de hacerme con el sistema de Parse (servicio que recomiendo al 100%) lo siguiente que necesitaba era acceder a la cámara del sistema para que el usuario pudiera sacar una foto y usar dicha foto en la interfaz de mi App.

Lo primero es definir la interfaz, que para nuestro ejemplo será algo muy sencillo, un panel con un control de tipo Image y otro de tipo Button que será el que lleve al usuario a la aplicación de cámara para poder sacar la foto. Una vez sacada la foto la usaremos como fuente en nuestro control de imagen.


<StackPanel Orientation="Vertical">
    <Image x:Name="ImageControl" Height="100" />
    <Button x:Name="TakePhotoButton" Content="Sacar foto" Click="TakePhotoButton_Click" />
</StackPanel>

Deberemos tener algo similar en nuestra interfaz. En el código subyacente de nuestra página lo primero que debemos hacer es añadir las instrucciones using necesarias, que en este caso se reducen a una sola:


using Windows.Phone.Tasks

Así tendremos acceso a la clase CameraCaptureTask que nos facilita la tarea de acceder a la cámara integrada del sistema en caso de que la toma de imágenes no sea la característica principal de nuestra aplicación.

En nuestro código subyacente debemos declarar un miembro del tipo CameraCaptureTask dentro de la clase que representa nuestra página, de modo que podamos acceder a ella desde cualquier punto del código. Este miembro lo colocamos justo antes de nuestro constructor. Dicho constructor queda como sigue, donde inicializamos el objeto CameraCaptureTask y le asignamos su event handler.

public PageConstructor()
{
    InitializeComponent();
    _cameraCaptureTask = new CameraCaptureTask();
_cameraCaptureTask.Completed += new EventHandler<PhotoResult>(CameraCaptureTask_Completed);
}

Cuando se saque la foto correctamente y se vuelva a nuestra aplicación se ejecutará el método  CameraCaptureTask_Completed que debemos definir en nuestra clase.

private void CameraCaptureTask_Completed(object sender, PhotoResult e)
{
    if (e.TaskResult == TaskResult.OK) // Si todo ha ido bien mostramos la foto
    {
         // Creamos un objeto BitmapImage que luego pondremos como fuente de nuestra imagen
        System.Windows.Media.Imaging.BitmapImage bmp = new System.Windows.Media.Imaging.BitmapImage();
        bmp.SetSource(e.ChosenPhoto); // ChosenPhoto es el Stream de datos que representa la foto capturada
        ImageControl.Source = bmp; // Colocamos el BitmapImage como fuente de la imagen
    }
}

Cabe mencionar que la foto capturada se guardará en la Biblioteca de la Cámara de Fotos, por lo que se podrá acceder a ella en cualquier otro momento. Para terminar, solo necesitamos lanzar la aplicación de la cámara para que el usuario saque su foto. Esto lo hacemos en el event handler de nuestro botón, que queda así

private void TakePhotoButton_Click(object sender, EventArgs e)
{
    _cameraCaptureTask.Show(); // Mostramos la aplicación cámara al usuario
}

Así de fácil, con esto se abrirá la cámara del sistema en cuanto nuestro usuario pulse el botón y, en cuanto saque y de por buena la foto, el control volverá a nuestra App y se ejecutará el método que hemos asignado a la señal Completed, mostrándonos la foto en nuestro control de imagen.

Para más información sobre la cámara en Windows Phone 8, las APIs LocalFolder y MediaLibrary no olvides visitar:

Posted in C#, Windows Phone | Tagged , , , , | 1 Comment

Cargar elementos en una lista si no quieres/sabes implementar ISupportIncrementalLoading en aplicaciones Windows Store

Hace un tiempo comencé a implementar un cliente “estilo Metro” para el servicio web Snipt, un servicio que permite guardar, compartir o descubrir “snippets” o trozos útiles y altamente reutilizables de código. La UI del cliente es muy simple y está casi completamente hecho a partir de las plantillas de Visual Studio 2012 para aplicaciones estilo Metro, en concreto con la llamada Split Page.

Los elementos del feed público del servicio se van cargando en la página principal (la primera que ve el usuario) y según la que esté seleccionada se muestra el código en un recuadro en la parte derecha. Hasta aquí todo bien, la chicha llega cuando queremos cargar los elementos desde la web a nuestra aplicación. ¿Cuántas cargamos a la vez? ¿Las cargamos al inicio de la aplicación o en la construcción de la página? Podríamos cargar las 4 ó 5 primeras páginas del feed público, pero nos llevaría muchísimo tiempo y eso haría esperar al usuario, incumpliendo el principio de ser rápido y fluido del lenguaje de diseño Metro. Podríamos cargar unos pocos rápidamente pero si no cargamos más al usuario casi le compensaría más visitar la web del servicio debido a la escasez de resultados.

Así pues lo ideal es cargar cuanto más ítems mejor, pero mostrando una partida inicial al usuario para que pueda empezar a interactuar de inmediato con nuestra aplicación mientras los demás ítems se cargan en un segundo plano y se añaden a nuestra lista cuando ya están descargadas. Este resultado se puede alcanzar de dos maneras, creando una clase personalizada que implemente la interfaz ISupportIncrementalLoading que permitirá cargar más ítems cuando el usuario esté llegando al final de la lista que le presentamos inicialmente; o bien cargando unos pocos ítems para no ralentizar la aplicación, y seguir cargando más ítems en segundo plano. La primera opción es la más idónea en cuanto que se ajusta mejor al propio diseño Metro y tiene un comportamiento más natural y además cargará automáticamente más ítems según el usuario lo requiera, pero si te pasa como a mi, que no he podido implementar dicha interfaz sin romperme la cabeza, siempre puedes tirar por la segunda solución para salir del paso de una manera medianamente elegante.

El plan

Lo que haremos será cargar una cantidad pequeña de ítems al inicio de nuestra aplicación aprovechando el tiempo que nos da el Splash Screen de nuestra aplicación, digamos que cargamos 10 ítems. Una vez cargados le presentamos al usuario nuestra página principal con esos 10 ítems cargados pero a la vez seguiremos cargando una cantidad mayor de ítems y cuando los tengamos listos los añadiremos a la lista que ve el usuario, así ofrecemos una cantidad de ítems interesante para el usuario manteniendo nuestra aplicación rápida y sin bloqueos.

La implementación

En mi caso tengo una clase que realiza todas las llamadas y peticiones al servicio web, llamada genéricamente ApiManager. Esta clase tiene un miembro de tipo ObservableCollection<Snippet> llamado Snippets que contiene como veis una clase personalizada llamada Snippets y que debéis reemplazar por el tipo de ítems que useis en vuestra aplicación.

ApiManager también cuenta con un método encargado de obtener los ítems del timeline público del servicio web y que tiene una firma como la siguiente:


public async Task GetPublicSnippets(ObservableCollection<Snippet> list, int? limit, int offset)

Lo primero que recibe es una lista de elementos que rellenará con lo que le llegue del servicio web, y en este caso en concreto se le puede poner un límite para cargar una cantidad determinada de ítems y un “desfase” para empezar a cargar a partir de cierto número de ítems.

Dentro de este método se realiza una petición web de tipo GET, se convierte la respuesta JSON a un objeto nativo .NET (en este caso una lista de elementos) y se van añadiendo elementos a la lista que se pasa como parámetro, llenando así la susodicha.

Lo que haremos será llamar a este método para que llene el miembro Snippets de ApiManager cuando se inicie el programa, así que buscamos el método OnLaunched en el archivo App.xaml.cs de nuestro proyecto y añadimos lo siguiente (el recurso “sniptApiManager” está declarado en App.xaml como un recurso de la aplicación)


SniptApiManager localManager = (SniptApiManager)App.Current.Resources["sniptApiManager"];

if (localManager != null)

    if (localManager.Snippets.Count == 0)

        await localManager.GetPublicSnippets(localManager.Snippets, 10, 0);

Con esto cargamos los primeros 10 ítems de manera asíncrona (si no estás muy puesto en el funcionamiento de los nuevos métodos asíncronos de .NET 4.5 mira aquí), ahora solo falta mostrárselos al usuario. Busca el método LoadState en el archivo MainPage.xaml.cs (o como hayas llamado a tu página principal) y añade lo siguiente al comienzo del mismo

SniptApiManager localManager = (SniptApiManager)App.Current.Resources["sniptApiManager"];

this.DefaultViewModel["Group"] = localManager;
this.DefaultViewModel["Items"] = localManager.Snippets;

Aquí agrego el objecto “contenedor” de elementos como el grupo del modelo de datos, y el miembro Snippets como el conjunto de ítems a mostrar. Aquí podremos usar tanto ObservableCollection como List<T> u otro objeto de lista. Agregando ambos elementos al modelo de datos la UI de nuestra aplicación se actualizará ella solita y el usuario podrá interactuar con estos datos. Pero aún no hemos terminado, ahora vamos a cargar otros 20 ítems más; justo después de estas líneas añadimos lo siguiente

if (localManager.Snippets.Count < 30)
{
await localManager.GetPublicSnippets(localManager.Snippets, null, localManager.Snippets.Count);
}

La condición está puesta para que nuestra página no añada más elementos una vez alcanzado los 30 (sin un límite fijo el miembro Snippet de ApiManager crecería sin fin y acabaría ocupando una cantidad de memoria exagerada), y para que no cargue los ítems que ya tenemos usamos el parámetro offset para que ApiManager descargue a partir del último ítems que conseguimos del servicio web.

Fíjate en que no hace falta añadir más, pues al actualizar el objeto asignado al modelo de datos, este mismo se actualiza automáticamente sin que tengamos que preocuparnos de reasignar el objeto al modelo de datos. De esta forma hemos cargado una buena cantidad de ítems sin congelar nuestra aplicación ni hacer esperar demasiado al usuario.

Página inicial de Snipts

Página inicial de Snipts

Cosas por mejorar

Pues evidentemente, hacer una implementación de ISupportIncrementalLoading que sería lo ideal en este tipo de escenarios, pero al margen de eso hay ciertas cuestiones que pueden mejorar la experiencia del usuario por ejemplo, agregar una barra de progreso indeterminado en la parte superior de la página, indicando al usuario de que, aunque puede interactuar sin problemas con la aplicación, aún se está realizando algún trabajo en segundo plano (cargar más ítems en nuestro caso).

También se podría guardar la posición del elemento seleccionado antes de añadir los nuevos ítems, para así no volver al primer elemento una vez cargados y desconcertar al usuario.

Posted in C#, Windows 8 | Tagged , , , , , , | Leave a comment

La fragmentación, el cancer de Linux en el escritorio

Muchos usuarios del software libre y el open source defienden la fragmentanción en el escritorio Linux con el débil argumento de que la base del software libre es la libertad de elección y demás tonterías. Mentira señores, la base de software libre se refiere a una libertad referente al código fuente y a como se interactua con este código por parte de los desarrolladores, pero la realidad es que la fragmentación de proyectos lo único que hace es debilitar aún más los avances de Linux sobre el mercado de escritorio.

Con la llegada de GNOME Shell y Unity el escritorio en Linux empezó a despedazarse a marchas forzadas en multitud de proyectos que intentaban replicar o imitar paradigmas de escritorios antiguos con el argumento de que “eran mejores” o “más cómodos” para justificar dicha fragmentación.

Antes de este escenario no había muchas opciones, las principales eran GNOME y KDE, y luego con un nicho más reducido unos cuantos entornos dedicados a sistemas y aparatos muy específicos como PCs de bajos recursos. Pero con la llegada de GNOME 3 y su nuevo paradigma de escritorio, una bombillita se encendió en la cabeza de varios desarrolladores que se apresuraron en asegurar que la nueva propuesta no servía y en menos que canta un gallo se lanzaron a programar sus “alternativas” para recuperar “lo perdido”.

Así empezaron a aparecer noticias sobre las nuevas alternativas a Shell, como Mate, Cinnamon, Pantheon, etc, etc. Un montón de proyectos llevados por gente de talento que lo único que lograba era separar a los usuarios, crear un montón de escritorios inestables y con un desarrollo lento para cumplir sus exigencias y caprichos personales. Cada uno buscando imitar lo que fuera GNOME 2 con un resultado dispar y duplicando el trabajo ya logrado y superado por otros proyectos más grandes y maduros.

Y todo esto ¿Ha traído algo verdaderamente bueno a Linux en el escritorio? En mi opinión, no, lo único que ha traído esto ha sido que todo el talento que está del lado del open source se disperse en proyectos que avanzan lentamente y que tienen una cantidad de usuarios más bien insignificante, cada uno creando nuevas aplicaciones para reemplazar a otras que ya existen y cumplen perfectamente su objetivo pero que “no encajan con los ideales del proyecto”, duplicando trabajo ya hecho para ofrecer “el mejor escritorio” (siempre es el mejor escritorio) dejando de lado fallos verdaderamente importantes de los que se tienen que encargar los proyectos mayores en los que se basan todos estos nuevos escritorios y proyectos.

Lo más gracioso de todo es que un escenario similar se dió con el cambio de KDE 3.X a la rama 4, pero sin embargo en aquel momento no aparecieron multitud de forks para recuperar KDE 3, uno, como mucho dos, pero no más, la rama 4 pronto se estabilizó y volvió a atraer a los usuarios perdidos convirtiéndose en el escritorio más avanzado tecnológicamente hablando para Linux; con GNOME, en cambio, y con Canonical y Unity como punto de partida, se dió el caso de que los usuarios en vez de apoyar y mejorar el proyecto principal (Shell) se han dedicado a tirar cada uno por su lado, dividiendo esfuerzos en vez de unificarlos que es lo que, creo yo, necesita el escritorio Linux al menos por el lado de GNOME. Unity tiene el apoyo de Canonical que se lo está currando de lo lindo para darle facilidades a los desarrolladores y atraer a estos a su plataforma que se ve reforzada con cada nueva versión de Ubuntu. KDE tiene una comunidad fiel y activa, y la ventaja que da tener como pilar base el mejor toolkit libre (Qt) que hay. Mientras tanto, GNOME sigue sin tener un rumbo fijo, dedicándose a mejorar lo que ya tienen, y con clónicos de GNOME 2 saliéndole como setas.

Esto lo único que produce en un usuario novato es rechazo y miedo, pues tiene diez mil alternativas distintas que a priori parecen hacer lo mismo, pero a la hora de la verdad todas comparten fallos y bugs heredados de sus proyectos “padres” y solo se diferencian en aplicaciones instaladas por defecto y que, como ya he dicho, solo son un sustituto para otras que cumplen con su objetivo pero no cuadran dentro del proyecto, ya sea porque no cumple con las reglas de diseño del nuevo escritorio, porque tiene dependencias consideradas no necesarias o no deseables por los líderes. El inconveniente de esto es que al saltar entre escritorios, o instalar en uno aplicaciones diseñadas para otro, nuestro PC parece una mala mezcolanza, una especie de Frankenstein mal diseñada donde cada aplicación se comporta de una manera distinta dependiendo de su entorno “padre”, y en definitiva, confundiendo a cualquier usuario.

Así pues, en mi opinión el escritorio en Linux está pasando por un momento complicado, y según lo que veo el que tiene más papeletas para salir mejor parado es la propuesta de Ubuntu (Unity), por el gran soporte y apoyo de parte de Canonical y la gran aceptación que están teniendo sus últimas versiones entre los usuarios; mientras tanto, las demás alternativas de escritorio que intentan aferrarse a paradigmas anticuados seguirán con su lento desarrollo, desperdiciando talento de la manera más ineficiente y menos práctica posible.

Posted in Open Source, opinión, Ubuntu | Tagged , , , , | 3 Comments

Así como veis el blog se ha remodelado por completo, mucho más dinámico, mejor diseñado y en definitiva, mejor. Espero con esto poder escribir más asiduamente que en el fondo es de lo que se trata cuando uno tiene un blog, y así poder dedicar más tiempo al desarrollo que es realmente lo mío. Así, muchas gracias por tu visita y espero verte por aquí más a menudo.

Posted on by Garolard | Leave a comment