Artículos etiquetados con:android
LiveData: todo sobre el componente de arquitectura Android

LiveData es quizás el componente más necesario y útil de Android Architecture Components. Se trata de una envoltura observable para nuestros datos con la ventaja de que está asociado a un ciclo de vida (de un fragment o activity).

En este post veremos con detalle cuáles son sus ventajas y qué usos podemos darle.

 

 

VENTAJAS

 

  • Tu UI siempre mostrará los datos más actualizados. LiveData no deja de ser un Observable vitaminado. Si construimos nuestra UI para que recoja la información a mostrar observando objetos LiveData, cualquier cambio que se produzca en estos datos será transmitido a cualquier vista o componente que lo esté observando. Esto significa que siempre se mantendrán actualizados.
  • No más errores ni código defensivo para evitar activities/fragments inactivos. Como LiveData está asociado al ciclo de vida de la activity o fragment, no se producirán llamadas a sus observables si la vista no está activa.
  • Tus datos siempre actualizados. Si la vuelta de un servicio ocurre cuando nuestra activity está en segundo plano, ese valor se almacena en el objeto LiveData. Además, en cuanto esa activity vuelva a estar activa, lo notificará inmediatamente a los observadores relacionados.
  • Evita Memory Leaks. Los observadores están asociados a un objeto con ciclo de vida. En el momento que ese objeto es destruido, los observadores se liberan de memoria.

 

 

USOS

La clase LiveData<T> es un objeto abstracto que no podemos instanciar como tal. Para la creación de estos objetos usaremos la clase MutableLiveData<T> la cual ya implementa todo lo necesario. Declaramos ese objeto en nuestro ViewModel, Repositorio o incluso en un Presenter de esta forma:

private final MutableLiveData<User> mUserInfoLiveData = new MutableLiveData<>();

NOTA: Recomiendo encarecidamente el salto a ViewModel, tiene muchas más ventajas que un Presenter al uso.

Para añadir o modificar un valor se usan los métodos setValue (si estás en el hilo de UI) o postValue (si estás en segundo plano). La diferencia entre ellos es que setValue alerta a los observadores inmediatamente, y postValue crea un Task para alertarlos en UI. En este segundo caso, si cambiamos los valores muy rápidamente, los observadores podrían recibir solo el último valor. En la mayoría de casos no nos importa, pero si necesitamos leer todos los valores que se emitan, es mejor utilizar setValue aunque tengamos que cambiar de hilo.

User user = ws.getUserInfo();
mUserInfoLiveData.setValue(user); // Si estamos en UI
mUserInfoLiveData.postValue(user); // Si estamos en segundo plano

Ya tenemos nuestro LiveData y estamos actualizando su valor, sólo nos queda que la vista reaccione a sus cambios.

El primer paso es exponer este objeto con un getter. Una buena práctica que nos ayuda a limitar la modificación de ese MutableLiveData a la propia clase en la que se encuentra es devolverlo como LiveData. Esto es así porque los métodos setValue y postValue no están implementados en LiveData, por lo que no podrán modificarse fuera de esta clase. Si necesitamos que se pueda modificar, es mejor añadir una función que lo actualice antes que exponerlo como MutableLiveData:

public LiveData<User> getUser(){
    return mUserInfoLiveData;
}

public void updateUser(User userUpdated){
    mUserInfoLiveData.postValue(userUpdated);
}

Una vez que tenemos los getters, vamos a usarlos para observar desde la vista. Para esto se usa el método observe, al que hay que pasarle un objeto con ciclo de vida y un observador. Este observador se asociará con ese ciclo de vida, de forma que se alertará cuando esté activo y se destruirá cuando el ciclo de vida también se destruya.

ViewModel viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
viewModel.getUser().observe(this, new Observer<User>() {
    @Override
    public void onChanged(@Nullable User user) {
       if(user != null){
          mName.setText(user.getName());
          mEmail.setText(user.getEmail());
       }
    }
);

 

 

RESOURCE

Hasta aquí todo parece muy bonito, pero te debes estar planteando una serie de dudas. ¿Qué pasa si ocurre un error al obtener el usuario? ¿Cómo se entera la vista en ese caso? Además, al ser una llamada WS, es recomendable dar feedback de esa petición con un loader, ¿cómo se entera la vista?

Hay varias soluciones a estos planeamientos, desde tener más objetos LiveData en el ViewModel, como por ejemplo MutableLiveData<String> mErrorLiveData o MutableLiveData<Boolean> mLoadingLiveData. Pero esto nos parece rizar el rizo, y al final se empieza a hacer una bola de nieve difícil de manejar.

Desde Google, en uno de sus ejemplos, han usado una clase Resource para envolver al dato en cuestión y manejar estos estados. Adaptando el ejemplo anterior quedaría de la siguiente forma:

 

VIEW MODEL

private final MutableLiveData<Resource<User>> mUserInfoLiveData = new MutableLiveData<>();

public UserViewModel(){
   mUserInfoLiveData.postValue(Resource.loading());
   User user = ws.getUserInfo(new WsCallback(){
       @Override
       public void onSuccess(User user) {
          mUserInfoLiveData.postValue(Resource.success(user));
       }

       @Override
       public void onError(String errorMessage) {
          mUserInfoLiveData.postValue(Resource.error(errorMessage));
       }
   });
}

public LiveData<Resource<User>> getUser(){
    return mUserInfoLiveData;
}

public void updateUser(User userUpdated){
    mUserInfoLiveData.postValue(Resource.success(userUpdated));
}

 

FRAGMENT

ViewModel viewModel = ViewModelProviders.of(this).get(UserViewModel.class);
viewModel.getUser().observe(this, new Observer<Resource<User>>() {
    @Override
    public void onChanged(@Nullable Resource<User> resource) {
       if(resource != null){
           switch (listResource.status){
              case SUCCESS:
                 setLoading(false);
                 mName.setText(resource.data.getName());
                 mEmail.setText(resource.data.getEmail());
                 break;
              case ERROR:
                 setLoading(false);
                 showErrorMessage(resource.message);
                 break;
              case LOADING:
                 setLoading(true);
                 break;
           }

       }
    }
);

 

 

INTEGRACIÓN DE LIVEDATA CON OTRAS GALERÍAS

  • Room. Para las consultas se puede envolver los datos de retorno directamente con un LiveData. De esta forma, Room se encarga tanto de la creación del objeto LiveData como de su actualización en tiempo real ante cualquier cambio en esa consulta.
  • Data Binding. El soporte para LiveData se encuentra desde la versión 3.1 de Android Studio, concretamente desde Android Studio 3.1 Canary 6. Desde esta versión se añade soporte para que nuestro layout se actualice automáticamente si bindeamos con objetos LiveData.

 

 

LIVEDATA: UN MUST

Si has leído hasta aquí, ya lo sabes todo para empezar a usarlo. No hay excusa que valga ya que la curva de aprendizaje es mínima. Te aseguro que es un verdadero gustazo salir del Callback-Hell y manejar todos los datos de nuestra UI con observables.

Además, nuestro código queda mucho más simple y fácil de entender. Esto hace más sencillo cualquier cambio en la clase al tiempo que de reducir la aparición de errores.

 

¡¡Corred a implementarlo, insensatos!!


Qué es y cómo elaborar un Code Style

Cuando somos pequeños y estamos empezando a escribir es importante seguir unas pautas para que todo el mundo entienda nuestra letra. Decir “¡pero si yo lo entiendo claramente!” no sirve de nada.

Siguiendo este símil, a la hora de escribir código es de suma importancia hacerlo de forma clara, concisa y, ante todo, legible. En este post veremos qué es un Code Style, qué debería contener y por qué es tan importante a la hora de escribir código con buena letra.

 

¿QUÉ ES EL CODE STYLE?

Podríamos decir que es el cuadernillo Rubio de los desarrolladores. Se trata de un documento que reúne una serie de guías o pautas a seguir tanto en la estructura del código como en la forma de implementarlo.

 

¿POR QUÉ ES TAN NECESARIO?

Por norma general, en todos los equipos hay bastantes programadores, cada uno de su madre y de su padre, con sus manías o costumbres. Debido a esto, llegar a un consenso puede ser una batalla campal en los inicios pero, nos guste o no, tenemos que llegar a un acuerdo.

Lo importante de un buen Code Style es que no venga impuesto por nadie y se llegue a una correcta definición entre todas las personas del equipo. Además, estará siempre sujeto a cambios y actualizaciones. Es muy importante que se escuchen todas las propuestas y se lleven a foro para evaluarlas y estudiar su posible cabida. De esta forma, todos nos sentimos parte de él y lo acataremos sin problemas.

 

¿QUIÉN DEBE SEGUIRLO?

Todo el mundo, sin excepciones. No hay excusas para aplicar el Code Style en todos los proyectos. Ni por las prisas, presiones, ni nada por el estilo; el código debe ser claro siempre. De esta forma si alguien nuevo llega a nuestro proyecto, sus tareas no se convertirán en una muerte a pellizcos y evitaremos que sea casi imposible cualquier modificación en el código.

 

¿QUÉ DEBERÍA CONTENER?

A grandes rasgos, en las secciones de nuestro Code Style incluiremos:

 

NOMECLATURA UTILIZADA

Establecemos pautas para la definición de nombre de:

  • Ids. Cuanta más información demos, mejor.
    Ej: login__input__username
  • Clases e interfaces. Comenzar por mayúsculas, usar camel case, tener un nombre descriptivo y especificar a qué hace referencia la clase.
    Ej: LoginFragment, LoginActivity, etc.
  • Variables. Tienen que ser autodescriptivas (nada de aux1, aux2, etc.). Proporcionaremos además información adicional sobre su accesibilidad.
    Ej: private String mTriesToForceCloseApp.
  • Métodos. Al igual que las variables, serán autodescriptivos y comenzarán siempre por un verbo.
    Ej: clickOnAcceptBtn()

 

DEFINICIÓN DE BLOQUES FUNCIONALES

Es importante la distinción de bloques funcionales simplemente con un primer vistazo a nuestro código, evitando que todo el código esté apelotonado, complicando así su lectura y comprensión.

  • Try/catch. Los bloques catch nunca estarán vacíos y respetaremos tanto los saltos de línea como los espaciados.

    try {
        ejecutaUnMetodo();
     
    } catch (MyException e) {
        Log.e("MyTag", "Esto es un pete capturado");
    }
    
  • Switch. Separaremos los distintos case con un salto de línea si llevan un break para separar bloques funcionales. Para los case que tienen código pero no tengan un break, incluiremos una anotación para indicar que la ejecución sigue en el siguiente case.

    switch(entrada) {
        case 1:
        case 2:
            ejecutaMetodoUno();
            /* falls through */
        case 3:
            ejecutaMetodoDos();
            break;
     
        default:
            ejecutaCasoPorDefecto();
    }
    
  • Bucles. Respetaremos los espaciados y diferencias de bloques funcionales.

    while (condicion) {
     //- Código...
    }
    

 

BUENAS PRÁCTICAS

Ni que decir tiene que hay que seguir una serie de pautas para que nuestro proyecto cumpla los estándares de calidad y pueda pasar herramientas como SonarQube sin ningún tipo de problemas.

  • Saltos de línea. Es importante no abusar de los saltos de líneas y ponerlos siempre siguiendo unas pautas.
    Ej: En los patrones Builder después del operador “.”, en las condiciones después de “&&” o “||”, etc.
  • Uso de this. Lo usaremos sólo para salvar ambigüedades.

    public class A {
        private String mName;
        public boolean selected;   
     
     
        A (String name, Boolean selected) {
            mName = name;
            this.selected = selected;
        }
     
     
        public void setSelected(boolean selected) {
            this.selected = selected;
        }
    }

 

TRATAMIENTO DE EXCEPCIONES O FLUJOS INCOHERENTES

Nuestro código tiene que ser seguro, por ello, debemos controlar todas las excepciones y tener una app libre de crashes. Además debemos seguir una nomenclatura para el reporte de las excepciones cuando se usan herramientas de log de crashes, de esta forma serán más fáciles de solventar.

 

¿NUESTRO CÓDIGO NECESITA COMENTARIOS?

En principio no, ya que los nombres de los métodos y variables serán autodescriptivos. Además los métodos serán atómicos, consiguiendo que cada función haga una única tarea y pudiendo así entender qué se está haciendo y por qué con un primer vistazo. No obstante, podemos añadir comentarios para aclarar ciertas partes del código vinculados a la lógica de negocio con el fin de facilitar su comprensión.

 

EJEMPLO DE USO

A continuación vamos a ver un ejemplo muy simple de su aplicación:

Antes de aplicar Code Style:

//- Código aglutinado y de difícil lectura
	if(condicionA&&condicionB&&(condicionC||condicionD))
			//- Código

Después de aplicar Code Style:

boolean condicionE = condicionC ||
                        condicionD;
						
	//- Correcto espaciado y salto de líneas
	if (condicionA &&
			condicionB &&
			condicionE) {
		//- Código
	}

 

En resumen, aunque en un principio pueda parecer un engorro consensuar o llegar a un acuerdo sobre su uso, gracias al Code Style escribiremos un código que simplificará tanto nuestro trabajo como el de nuestros compañeros.


Cómo exportar un elemento desde Sketch a Zeplin

Hacer un app “fea” es mucho más difícil que hacerla bien. Eso opina nuestro equipo de diseño. Por el contrario, hay quien piensa que siendo diseñador gráfico todo lo relacionado con la estética se ve demasiado fácil.

Pero lo cierto es que en el desarrollo de apps móviles, existen algunos procesos y pequeños consejos que pueden ayudar, y mucho, a que el resultado final de la aplicación sea bastante aceptable sin necesidad de conocer la teoría del color según Kandinsky.

Paco Soria, diseñador del equipo de SDOS, nos explica en este vídeo cómo exportar un elemento desde Sketch a Zeplin. En pocos pasos, de forma clara y con algunos ejemplos aplicables tanto para Android como iOS.

¡Ya verás qué fácil!

 


Cómo compilar aplicaciones Android con Jenkins

En tiempos de desarrollo de software mediante metodologías ágiles, Scrum e integración continua, donde todos los miembros de un equipo integran su código frecuentemente y pueden realizar varias subidas al día dependiendo de las tareas a desarrollar, resulta imprescindible el uso de herramientas que permitan conocer en todo momento el estado del producto, las diferentes versiones y el estado en que se encuentra.

Cada vez que se realiza una subida de código al repositorio, se realiza una integración que compila el código fuente y verifica que se ha realizado correctamente, obteniendo un ejecutable de la aplicación. Para este proceso, en SDOS nos hemos decantado por el uso de Jenkins, un software gratuito y Open Source escrito en Java y está basado en el proyecto Hudson.

 

¿POR QUÉ JENKINS?

Este sistema soporta herramientas de control de versiones como SVN o GIT y puede ejecutar proyectos basados en Ant y Maven, Gradle, etc. Además, al ser un proyecto Open Source, es el más utilizado por los desarrolladores, contando con una gran comunidad de desarrollo y soporte.

Pero Jenkins no es sólo una herramienta para el equipo de desarrollo, también sirve al equipo de QA: del mismo modo que posibilita la ejecución de test automáticos o incluso el uso de Sonarqube, justo después de cada compilación permite comprobar la calidad de la subida.

 

¿CÓMO USAR JENKINS CON ANDROID?

En el desarrollo Android, Jenkins puede servirnos para generar un .apk cada vez que realicemos una subida de código al repositorio, guardándola en un servidor FTP donde tendremos un listado de todas las versiones generadas.

En este post os contamos cómo completar todo el proceso. ¡Empezamos!

 

1. CREAR UN PROYECTO EN JENKINS

En primer lugar, creamos un nuevo Job en Jenkins.

Paso 1 para compilar un .apk en Jenkins

A continuación, seleccionamos un nuevo proyecto Freestyle para poder configurarlo según nuestras necesidades. Escribimos un nombre y hacemos clic en OK.

Paso 2 para compilar un .apk en Jenkins

 

2. CONFIGURAR LAS SECCIONES DEL JOB

GENERAL

En esta sección definiremos lo siguiente:

  • Proyect name y description. Es recomendable dar un nombre intuitivo al proyecto y una descripción concreta para saber qué Job estamos ejecutando:

Paso 3 para compilar un .apk en Jenkins

  • Cuándo se descargan los builds antiguos. Es importante definir un número máximo de build a guardar ya que no queremos sobrecargar la máquina ni llenar de ejecuciones nuestro Job. Como recomendación, nos quedaremos con las 10 últimas ejecuciones realizadas. Si por necesidad del proyecto necesitamos que sean más, podría aumentarse el número, pero debería ser sólo en casos puntuales.

Paso 4 para compilar un .apk en Jenkins

  • Parámetros para ejecutar el proyecto. En la parte general también definiremos los parámetros necesarios para ejecutar un Job. Para añadirlos tenemos que hacer clic en This project is parameterized y seleccionar un Choice Parameter. Los parámetros para la compilación de una app de Android serán los siguientes:
    • Type. Por defecto en Android siempre aparecen dos tipos, debug y release, pero pueden añadirse tipos personalizados. En nuestro caso añadiremos: Release, Preproduction y Debug.
    • Flavors. Un flavor define una versión customizada de la aplicación. Esto nos permite definir diferentes personalizaciones de la aplicación dependiendo de la variante que necesitemos. Por ejemplo, podríamos tener un flavor para una demo de la aplicación y otro con la aplicación completa de pago.
    • Git Parameter. Definiremos como parámetro la rama que queremos del repositorio concreto. Tendremos que definir un valor por defecto para las ejecuciones automáticas. Si tenemos muchas ramas en un mismo repositorio, podemos hacer un filtro por nombre de rama como, por ejemplo, .*_rc.* (todas las ramas que incluyen _rc, release candidate).

Paso 5 para compilar un .apk en Jenkins

Paso 6 para compilar un .apk en Jenkins

 

Puedes encontrar más información sobre los parámetros en este enlace.

 

SOURCE CODE MANAGEMENT

En esta sección definiremos el tipo de repositorio que queremos usar, en nuestro caso será Git.

Una vez que seleccionamos la opción de Git tenemos que añadir:

  • URL del repositorio. Dónde está guardado el código del proyecto.
  • Credenciales. Usaremos en usuario git previamente añadido en Jenkins.
  • Branch. Especificaremos la rama específica del proyecto que usaremos. Como ya la hemos elegido una con el parámetro Git Parameter, le pasamos el valor de ese parámetro con $Branch.

Paso 7 para compilar un .apk en Jenkins

 

BUILD TRIGGERS

En esta sección definiremos el tipo de activador que necesitamos para ejecutar el build. Si no añadimos ninguno, sólo se ejecutará cuando nosotros lo forcemos. Desde aquí también podemos:

  • Realizar una ejecución remota desde un script.
  • Realizar la ejecución de forma periódica, por ejemplo cada noche a las 00:00.
  • Realizar una ejecución cuando se produzca un push o un new merge request en el repositorio.

Por ahora lo dejaremos por defecto y lo ejecutaremos manualmente.

 

BUILD ENVIROMENT

En esta sección definiremos dos opciones:

  1. Borrar la carpeta del workspace antes de cada ejecución (para realizar una ejecución limpia).
  2. Añadir el timestamp a los logs para tener más información.

Paso 8 para compilar un .apk en Jenkins

 

BUILD

En la sección del Build añadiremos un Execute shell para ejecutar los siguientes comandos:

Paso 9 para compilar un .apk en Jenkins

  • chmod +x gradlew: da permisos de ejecución al fichero gradlew por si no los tiene (por defecto ya los tiene).
  • ./gradlew: ejecuta el fichero gradlew en la máquina donde está Jenkins que es un Linux (¡cuidado con este fichero!).
  • assemble: es la orden para compilar una aplicación Android.
  • $Flavor: flavour elegido para la ejecución. Ponemos $ para que se sustituya el valor del parámetro por el seleccionado del desplegable flavor en la sección general.
  • $Type: type elegido para la ejecución. Ponemos $ para que se sustituya el valor del parámetro por el seleccionado del desplegable type en la sección general.

 

POST-BUILD ACTIONS

Desde esta sección realizaremos principalmente tres acciones:

  • Guardar el artefacto generado. Guardaremos todos los ficheros .apk generados en la compilación del proyecto. Por defecto lo guardaremos en: **/*.apk

Paso 10 para compilar un .apk en Jenkins

  • Enviaremos el fichero .apk dentro de la carpeta /apks/ a un servidor FTP. En nuestro caso, tenemos un servidor llamado NAS1 en el que guardaremos el apk generado en una carpeta ya creada dentro del servidor.Nota: para configurar la conexión con un servidor FTP debemos ir a Manage Jenkins > Configure Jenkins > Publish over FTP, y añadir los datos correspondientes a nuestro servidor.

Paso 11 para compilar un .apk en Jenkins

  • Enviar correo cada vez que termine un Build utilizando la acción post-build Editable Email Notification. La configuración que tendremos será la siguiente:

Paso 12 para compilar un .apk en Jenkins

 

Puedes copiar el contenido del mensaje por defecto de este HTML:

Default Subject

[JENKINS- ${JOB_NAME} ] Result of Build $BUILD_NUMBER ${JOB_NAME} Project.

Default Content

<html>
 
<p> Hello. </p>
 
<p>This mail is auto-generated as part of the Jenkins execution of the project <b>${JOB_NAME}</b> </p>
 
<h2> BUILD DETAILS: </h2>
 
<p>
       <b>Project Name:</b> ${JOB_NAME} <br>
       <b>Build URL:</b> ${BUILD_URL} <br>
       <b> Build Number: </b> ${BUILD_NUMBER} <br>
       <b>Build Status: </b> ${BUILD_STATUS} <br>
       <b>Type: </b> $Type <br>
       <b>Flavor: </b> $Flavor <br>
       <b>Branch: </b> $Branch <br>
       <b>Download APK: </b> ${BUILD_URL}/lastSuccessfulBuild/artifact/apks/ <br>
       <b>Log: </b> The log file is attached into this e-mail. <br>
       <b>Log URL: </b> ${BUILD_URL}${JOB_NAME}/lastBuild/console <br>
       <b>Changes: </b> ${CHANGES, format="List of changes: <li><ul>[%a] %m </ul><ul> [Date:] %d </ul> <ul> [Revision:] %r </ul></li> <br>"} <br>
</p>
 
<p> Thank you & Regards. </p>
 
</html>

 

Esta template es genérica para cualquier proyecto ya que usa las siguientes variables:

  • ${JOB_NAME}. Nombre del Job en el Jenkins.
  • ${BUILD_URL}. URL exacta del Job.
  • ${BUILD_NUMBER}. Número de Build ejecutado.
  • ${BUILD_STATUS}. Estado en el que ha finalizado el Build.
  • $Type. Tipo seleccionado al ejecutar el Build.
  • $Flavor. Flavor seleccionado al ejecutar el Build.
  • $Branch. Branch seleccionada al ejecutar el Build, si no se ha elegido ninguna aparece el nombre de la branch por defecto definida.
  • ${CHANGES}. Muestra los cambios realizados en el commit que ha activado el Build.
    • %a: autor del commit.
    • %m: mensaje del commit.
    • %d: fecha del commit.
    • %r: número de commit.

 

Esto dará lugar a un email como el que se muestra a continuación. Obtenemos así el .apk generado de forma sencilla.

Paso 13 para compilar un .apk en Jenkins

 

Sin lugar a dudas, en los últimos años Jenkins se ha convertido en una herramienta indispensable en el desarrollo de software ágil ya que, además de automatizar el proceso de producción de artefactos, garantiza la calidad en cada uno de ellos tanto para el cliente como para el propio equipo.


Android loves Kotlin: todo sobre el nuevo lenguaje de programación oficial

El pasado mes de mayo se celebró la edición anual de Google I/O, el evento donde la multinacional presenta las primicias que estarán a disposición de los usuarios de la gran G a corto y medio plazo, y también las novedades para los desarrolladores de las diferentes tecnologías relacionadas con su ecosistema.

Para Android, se presentaron características de la futura versión del sistema operativo, Android O: la nueva versión de la librería support, instant apps, las nuevas librerías para dar soporte a las arquitecturas de aplicaciones. Sin embargo, para mí y para muchos desarrolladores más, el anuncio más llamativo de todos fue la apuesta oficial por Kotlin como lenguaje de desarrollo Android.

¿Qué significa esto? Pues que a partir de la próxima versión 3.0 de Android Studio, podremos desarrollar aplicaciones para Android usando este lenguaje de programación, totalmente integrado por el IDE. Pero entremos un poco en materia.

 

¿QUÉ ES KOTLIN?

Kotlin es un lenguaje de programación de tipado estático que corre sobre la JVM que ha sido desarrollado por JetBrains, responsables de IntelliJ, IDE en el que se basa Android Studio (¡menuda casualidad!).

Aunque lleva fraguándose desde el año 2011, en febrero de 2016 se lanzó su primera versión estable 1.0 y este pasado marzo ya se actualizó a 1.1. Nació con la idea de sustituir a Java pero siendo totalmente interoperable con él y todo su ecosistema (para facilitar así la migración).

 

¿QUÉ APORTA KOTLIN QUE NO NOS DA JAVA?

Para dar una muestra de las bondades de Kotlin frente a Java, me voy a apoyar en las cuatro características que se mencionan en el libro “Kotlin for Android Developers” de Antonio Leiva, uno de los mayores referentes dentro de la comunidad Android y uno de los máximos promulgadores del nuevo lenguaje oficial de desarrollo.

  1. Expresividad
  2. Seguridad frente a nulos
  3. Funciones de extensión
  4. Programación funcional

 

1. EXPRESIVIDAD

Si queremos declarar una clase completa en Java tenemos que definir los getter, setter, toString, hashCode y equals. Por ejemplo, si definimos la clase “Dog”, tendríamos la siguiente clase Java:

public class Dog {
    
    private Long id;
    private String name;
    private String owner;
    private String breed;
 
    public Dog(Long id, String name, String owner, String breed) {
        this.id = id;
        this.name = name;
        this.owner = owner;
        this.breed = breed;
    }
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getOwner() {
        return owner;
    }
 
    public void setOwner(String owner) {
        this.owner = owner;
    }
 
    public String getBreed() {
        return breed;
    }
 
    public void setBreed(String breed) {
        this.breed = breed;
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
 
        Dog dog = (Dog) o;
 
        if (id != null ? !id.equals(dog.id) : dog.id != null) return false;
        if (name != null ? !name.equals(dog.name) : dog.name != null) return false;
        if (owner != null ? !owner.equals(dog.owner) : dog.owner != null) return false;
        return breed != null ? breed.equals(dog.breed) : dog.breed == null;
 
    }
 
    @Override
    public int hashCode() {
        int result = id != null ? id.hashCode() : 0;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + (owner != null ? owner.hashCode() : 0);
        result = 31 * result + (breed != null ? breed.hashCode() : 0);
        return result;
    }
 
    @Override
    public String toString() {
        return "Dog{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", owner='" + owner + '\'' +
                ", breed='" + breed + '\'' +
                '}';
    }
}

 

Como vemos, tenemos muchísimo código repetitivo (como casi todo en Java) para definir una clase. Sin embargo, todo eso lo podemos hacer en Kotlin de una forma muchísimo más sencilla.

data class Dog(var id: Long, var name: String, var owner: String, var breed: String)

 

Esto es sólo un ejemplo de que con mucho menos código podemos hacer muchas más cosas en Kotlin que en Java, y de una forma muy clara y legible.

 

2. SEGURIDAD FRENTE A NULOS

Cuando desarrollamos en Java, muchísimo código es defensivo. Esto supone que tenemos que comprobar continuamente cuándo algún objeto es nulo si no queremos encontrarnos con el típico error en tiempo de ejecución NPI. Sólo los tipos nativos no son nulos.

Dog dog = null;
Log.println(Log.INFO, "TEST", dog.getName());
#Este código se puede compilar, pero produce un NPI en tiempo de ejecución

 

Kotlin, sin embargo, como muchos otros lenguajes modernos, es seguro frente a nulos. Es decir, tenemos que especificar explícitamente cuándo un objeto puede ser nulo.

val dog1: Dog = Dog(lL, “Toby”, “Javi”, “Galgo”)
var dog2: Dog? = null
 
#Me permite compilar
dog1.print()
 
#No me permite compilar al no comprobar que es nulo
dog2.print()
 
#Con el operador ? si me deja hacerlo
dog2?.print()
 
#O como en Java
 
if(dog2 != null){
	dog2.print() 
}
#Ahora si compila, al estar dentro de un bloque donde se ha comprobado que no es nulo.
 
#Podemos usar el operador Elvis para dar un valor cuando la variable es nula
var name = dog2.name ?: “Desconocido”

 

3. FUNCIONES DE EXTENSIÓN

Con Kotlin podemos añadir nuevas funciones a cualquier clase de Java o Android con las funciones de extensión, que se entienden y son mucho más intuitivas que las típicas clases de utilidades que todo programador ha usado alguna vez.

Podemos, por ejemplo, añadir un método a un fragment para que muestre un toast de la siguiente forma:

fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGHT_SHORT){
	Toast.makeText(activity, message, duration).show
}
 
#Y lo podemos usar dentro de un fragment directamente:
toast.dog1.name

 

4. PROGRAMACIÓN FUNCIONAL

Realmente, con Java 8 podemos usar programación funcional con lambdas, pero éstas están bastante limitadas con respecto a todo el potencial que nos aporta Kotlin.

Dentro de un fragment con un TextView podemos implementar el típico onClickListener con una lambda de la siguiente forma:

textView.setOnClickListener {toast.dog2?.name}

 

EL FUTURO DE Y CON KOTLIN

Esto es sólo una pequeña muestra de todo el potencial que tiene este joven pero maduro lenguaje de programación. Podría contar más de las funciones sobre colecciones, properties, delegados, corrutinas, smartcast, etc., pero aún es un mundo por descubrir.

Actualmente, el equipo de desarrollo de Jetbrains está trabajando en Kotlin/Native, lo que significa que, en un futuro próximo, Kotlin podrá ser lenguaje para el desarrollo de aplicaciones iOS. Tendremos así la posibilidad de reutilizar código fuente con Android (¡qué bien suena!), sistemas embebidos o IoT (Arduino, por ejemplo), BigData, servicios, desarrollo de videojuegos, etc. En fin, el futuro.


Nuestro resumen de #Exfest16

Cáceres acogió este fin de semana la segunda edición de ExFest, evento en el que se han cita desarrolladores y reconocidos ponentes para compartir conocimientos y tendencias sobre las tecnologías de Google, tanto móvil como web.

A la cita acudió parte de nuestro equipo Android, quienes destacan el alto nivel de las conferencias y el valor aportado en materia de arquitecturas de aplicaciones, testing y resilencia de los sistemas operativos. Pudieron conocer también de primera mano la experiencia de aplicaciones como Twitter, donde se puso de manifiesto la importancia de la constante evolución de las apps móviles.

Desde SDOS queremos felicitar a GDG Cáceres por la organización. Ya esperamos con ganas la edición de 2017.


SDOS en el MaterialFest

Miembros de los equipos de movilidad y diseño de SDOS acudieron el pasado sábado a MaterialFest, la primera edición de un encuentro destinado a desarrolladores y diseñadores del sistema Android, un evento pensado para profesionales que “realmente hacen los productos hablando desde la experiencia”.

Con una asistencia de 350 profesionales y speakers internacionales de startups de éxito, la jornada se desarrolló entre charlas y tracks: uno enfocado en diseño digital (con charlas sobre tipografía, Material Design, iconografía y guías de estilo), otro enfocado en desarrollo Android (charlas sobre frontend en Android, animaciones y programación funcional) y otros eventos paralelos sobre UX y mesas redondas.

En definitiva, un evento para que, como apunta uno de nuestros desarrolladores, SDOS pueda ser más Material y Android si cabe.


Uso de cookies

Este sitio web utiliza cookies para que tengas la mejor experiencia de usuario. Si continúas navegando estas dando tu consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pincha el enlace para obtener más información.

ACEPTAR
Aviso de cookies