41
I wanna be an Superstar! Ignacio Muñoz Vicente @imunoz_ Buenas prácticas en el desarrollo de aplicaciones para Android

Android Superstar - Buenas Prácticas

Embed Size (px)

DESCRIPTION

Buenas prácticas en el desarrollo para Android. Consejos sobre: - Organización del código - Trucos en programación Java - Reutilización - Rendimiento - Compartición de datos - Usabilidad - Etc.

Citation preview

Page 1: Android Superstar - Buenas Prácticas

I wanna be anSuperstar!

Ignacio Muñoz Vicente @imunoz_

Buenas prácticas en el desarrollo de aplicaciones para Android

Page 2: Android Superstar - Buenas Prácticas

Orden y reutilización

Programar es algo más que programar

Antes de programar, piensa… !- Qué vas a necesitar - Qué vas a hacer - Qué elementos van a ser comunes - Qué problemas te vas a encontrar - Qué puedes reutilizar de otros proyectos

Page 3: Android Superstar - Buenas Prácticas

Orden y reutilización

Empaquetar adecuadamente

Es importante tener el código bien organizado y agrupado por funcionalidades. Sobre todo cuando el proyecto va creciendo

VS

Page 4: Android Superstar - Buenas Prácticas

Orden y reutilización

Encapsular, modularizar, crear libreríasMuchas funcionalidades son utilizadas constantemente: geolocalización, acceso a cámara, elementos gráficos propios, etc. !Desarrollar una vez —> utilizar infinitas !Extraer código común entre aplicaciones y pasarlo a librerías —> siguientes proyectos —> coste de desarrollo = 0

Librería 1 Librería 2 Librería 3 Librería 4 Librería 5

App 1

Utils

Módulo 1

Módulo 2

Módulo 3

App 2

Utils

Módulo 1

Módulo 2

Módulo 3

Page 5: Android Superstar - Buenas Prácticas

Ejemplos

Orden y reutilización

Nomenclatura estandarizada de recursosEn proyectos grandes con muchos recursos puede resultar imposible identificar los mismos rápidamente si no se sigue una nomenclatura !No hay una nomenclatura mundial. Google recomienda algo, pero poco

Activity: activity_XXXX.xml Fragment: fragment_XXXX.xml Item adapter: item_XXXX.xml !Imagen ActionBar: ic_actionbar_XXXX.xml Imagen botón: ic_btn_XXXX.xml !Clase Activity: XXXXActivity.java Clase Fragment: XXXXFragment.java Clase Utiles: XXXXUtils.java Clase Adapter: XXXXAdapter.java …

Page 6: Android Superstar - Buenas Prácticas

Orden y reutilización

Utilizar Fragments… siempre!FragmentActivity es tu amigo !Convertir una aplicación para smartphones en una aplicación universal resultará más sencillo si utilizamos Fragments desde un principio

Smartphone Tablet

Activity A Activity AActivity B

Fragment A Fragment B Fragment A Fragment B

Page 7: Android Superstar - Buenas Prácticas

Orden y reutilización

<include> y <merge>No sólo el código Java se reutiliza. Reutiliza también partes de la interfaz que se repiten en varias ventanas !<merge> además permite evitar vistas enlazadas sin utilidad

titlebar.xml<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width=”match_parent” android:layout_height=“wrap_content" android:background="@color/titlebar_bg"> ! <ImageView android:layout_width=“wrap_content" android:layout_height="wrap_content" android:src="@drawable/gafricalogo" /> </FrameLayout>

a_layout.xml…

<include layout=“@layout/titlebar"/> …

any_other_layout.xml…

<include layout=“@layout/titlebar"/> …

Page 8: Android Superstar - Buenas Prácticas

Orden y reutilización

Layouts y dimensTrabajar con las distintas resoluciones de pantalla no es tan complicado con un uso correcto de estos elementos !Si son distintos diseños para cada resolución —> utilizar distintos layouts !Si son el mismo diseño pero cambian las medidas —> utilizar archivos dimens.xml

a_layout.xml

values/dimens.xml…

<dimen name=“text_title”>14sp</dimen> …

values-sw600dp/dimens.xml

<TextView … android:textSize=“@dimen/text_title” … />

… <dimen name=“text_title”>22sp</dimen>

Page 9: Android Superstar - Buenas Prácticas

Contantes siempre como static finalLas constantes deben ir siempre como “static final” !Los nombres de extras en un Intent siempre como constantes !Los nombres de ContentValues también como constantes

Orden y reutilización

public static final String EXTRA_INVENTADO = “inventado”; !… !Intent intent = new Intent … intent.putExtra(EXTRA_INVENTADO, 5); startActivity(intent); private static final String DB_USUARIO_NOMBRE = “nombre”;

private static final String DB_USUARIO_EDAD = “edad”; !… !ContentValues values = new ContentValues(); values.put(DB_USUARIO_NOMBRE, “Nacho”); values.put(DB_USUARIO_EDAD, 27);

Page 10: Android Superstar - Buenas Prácticas

Orden y reutilización

Imágenes en la carpeta adecuada

Según la densidad de las pantallas cargará una imagen u otra !Si falta la imagen en una carpeta, Android la cargará de otra y la escalará según corresponda

Page 11: Android Superstar - Buenas Prácticas

Orden y reutilización

Uso correcto de private, public y protected

No hacer accesibles variables o métodos donde no deban serlo

Clase Paquete Subclase Otros paquetes

public SI SI SI SI

protected SI SI SI NO

() SI SI NO NO

private SI NO NO NO

Page 12: Android Superstar - Buenas Prácticas

Orden y reutilización

Imágenes 9-patchLos elementos gráficos son de distintos tamaños según densidades y resoluciones !La solución sencilla es el uso de imágenes 9-patch, que indican que parte de las mismas se pueden estirar y cuales no !Herramienta draw9patch (Android SDK) !Herramientas online (http://romannurik.github.io/AndroidAssetStudio/nine-patches.html)

Page 13: Android Superstar - Buenas Prácticas

Orden y reutilización

Reutilizar y comprimir imágenesUtilizar misma imágenes con transformaciones !AAPT y otras herramientas para comprimir imágenes sin perder calidad !Reduce el tamaño del APK final

<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="90" android:toDegrees="90" android:pivotX="50%" android:pivotY="50%" android:drawable="@drawable/arrow"> </rotate>

Page 14: Android Superstar - Buenas Prácticas

Rendimiento

Ciclo de vida

Conoce bien cómo funciona una aplicación y por qué estados pasan sus actividades (fragments, aplicación y resto de elementos) !Una Activity pasa por todos los estados excepto en un caso —> finish() en onCreate !En el método onPause —> parar acciones que consuman GPU o batería !En el método onStop —> guardar datos para evitar su pérdida !

Page 15: Android Superstar - Buenas Prácticas

Rendimiento

Uso correcto de ContextHay varios Context disponibles en Android !Hay que tener cuidado con las referencias al Context de las Activities

1. Mediante FLAG_ACTIVITY_NEW_TASK 2. Carga el Theme del sistema en ese momento, no el de la aplicación

Memory leak!- No hay que mantener en memoria referencias al Context de una Activity - Utilizar mejor el Context del Application en las referencias

Page 16: Android Superstar - Buenas Prácticas

Rendimiento

Adapters, ViewHolders y carga asíncronaAndroid sólo mantiene en memoria las vistas de los items que se encuentran visibles en ese momento en pantalla —> si vamos haciendo scroll se crean y se destruyen vistas indefinidamente —> (solución) reutilizamos la vista que viene como parámetro. !La invocación a findViewById es muy costosa —> (solución) Utilizaremos ViewHolder !Los elementos pesados o que pueden tardar en cargar ralentizar la interfaz —> (solución) Cargar en background (AsyncTask)

static class ViewHolder { TextView titulo; TextView subtitulo; }

public View getView(int position, View convertView, ViewGroup parent) { View item = convertView; ViewHolder holder; if (item == null) {! LayoutInflater inflater = context.getLayoutInflater(); item = inflater.inflate(R.layout.item_ejemplo, null); holder = new ViewHolder();! holder.titulo = (TextView)item.findViewById(R.id.LblTitulo); holder.subtitulo = (TextView)item.findViewById(R.id.LblSubTitulo); item.setTag(holder);! } else {! holder = (ViewHolder)item.getTag();! }! holder.titulo.setText(datos[position].getTitulo()); holder.subtitulo.setText(datos[position].getSubtitulo()); return(item); }

Page 17: Android Superstar - Buenas Prácticas

Rendimiento

Uso responsable de variables

Tener referencias a variables que no se utilizan nunca es bueno —> Síndrome de Diógenes !Lo mismo con librerías e imports no necesarias

Page 18: Android Superstar - Buenas Prácticas

Rendimiento

Cuidado variables estáticas o de clase

Hay que evitar su uso siempre que no sea imprescindible !Se mantienen en memoria durante más tiempo que las variables de instancia —> No será eliminada por el recolector de basura

public class MiClase { private static Context elContexto; ! public MiClase(Context contexto){ elContext = contexto;! } } Irás al infierno

Page 19: Android Superstar - Buenas Prácticas

Rendimiento

Bitmaps: amor / odio

En memoria lo justo Cargar en memoria Bitmaps del tamaño a utilizar: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html !Carga en background Los métodos BitmapFactory.decode* no deben ejecutarse en el thread principal —> AsyncTask: http://developer.android.com/training/displaying-bitmaps/process-bitmap.html Utilizar cache !Recycle Una vez deja de ser necesario un Bitmap debemos liberarlo de memoria a través de recycle() Es importante ya que el recolector de basura existente en Android no es suficiente Ojo! Debemos estar seguros que no se va a utilizar el Bitmap después. Campo ‘inBitmap’ a partir de versión 3.0 !WeakReference En versiones antiguas con poca memoria utilizar WeakReference para referencias a Bitmaps (permiten al recolector de basura liberar esos objetos de memoria)

Page 20: Android Superstar - Buenas Prácticas

Rendimiento

StringBuilder

Si vamos a ir concatenando o modificando el valor de una cadena de texto lo ideal es utilizar StringBuilder —> Si utilizamos la clase String se creará un objeto String por cada concatenación o cambio de la cadena

String StringBuilder

String test = “test”; test += “ y un nuevo test”; test += “ y otro nuevo test”; test += “ y otro más concatenado”;

StringBuilder testBuilder = new StringBuilder(); testBuilder.append(“test”); testBuilder.append(“ y un nuevo test”); testBuilder.append(“ y otro nuevo test”); testBuilder.append(“ y otro más concatenado”); !String test = testBuilder.toString();

4 Objetos 2 Objetos

Page 21: Android Superstar - Buenas Prácticas

Rendimiento

Métodos estáticos

Siempre que sea posible debemos utilizar métodos estáticos !Son entre un 15% y un 20% más rápidos que los métodos de instancia !Evitan también tener que instanciar objetos para ser invocados

Page 22: Android Superstar - Buenas Prácticas

Rendimiento

Evitar usos de getters innecesariosDentro de una clase se recomienda acceder directamente a través de la variable, y no a través de su método getter

public class MiClase { !private String miVariable; ! … !public String getMiVariable() { return miVariable; } !public void formaIncorrecta() { Log.d(TAG, “miVariable es”+getMiVariable(); } !public void formaCorrecta() { Log.d(TAG, “miVariable es”+miVariable; }

Page 23: Android Superstar - Buenas Prácticas

Rendimiento

Evitar entrelazar muchas vistasCuantas más vistas se entrelazan o más niveles existente en ellas, más tarda el dispositivo en cargar la ventana

Measure: 0.977ms Layout: 0.167ms Draw: 2.717ms

Measure: 0.598ms Layout: 0.110ms Draw: 2.146ms

=

Page 24: Android Superstar - Buenas Prácticas

Rendimiento

CompoundDrawableSe recomienda utilizar un TextView con un CompoundDrawable en vez de utilizar un ImageView junto a un TextView

<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> ! <ImageView android:layout_width=“wrap_content" android:layout_height=“wrap_content" android:src="@drawable/imagen"> </ImageView> ! <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="2dp"> </TextView> !</LinearLayout>

= <TextView android:drawableLeft="@drawable/imagen" android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawablePadding=“2dp"> </TextView>

Page 25: Android Superstar - Buenas Prácticas

Rendimiento

ViewStubCarga de elementos de la interfaz por petición !ViewStub no tiene medidas ni contenido inicial —> barato en cuanto a rendimiento y carga !

Uso

<ViewStub android:id="@+id/stub_import" android:inflatedId="@+id/panel_import" android:layout="@layout/progress_overlay" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" />

Carga

((ViewStub) findViewById(R.id.stub_import)) .setVisibility(View.VISIBLE); !// o !View importPanel = ((ViewStub) findViewById(R.id.stub_import)). inflate();

Page 26: Android Superstar - Buenas Prácticas

Rendimiento

HTTPURLConnectionMejor HTTPURLConnection que HTTPClient !!!!!!!- API más sencilla !- Mejoras en compresión y cacheo —> velocidad y ahorro de batería !- Soporte a SNI (Server Name Indication)

InputStream is = null; try { URL url = new URL(myurl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(10000 /* milliseconds */); conn.setConnectTimeout(15000 /* milliseconds */); conn.setRequestMethod("GET"); conn.setDoInput(true); // Conectar conn.connect(); int response = conn.getResponseCode(); is = conn.getInputStream(); ! // Tratar respuesta // …. !} finally { if (is != null) { is.close(); } }

Page 27: Android Superstar - Buenas Prácticas

Internal Storage VS External Storage

Almacenar y compartir datos

Los datos guardados en la memoria interna sólo son accesibles por la misma aplicación Los datos son eliminados si se desinstala la App !Los datos guardados en la memoria externa pueden ser accedimos por otras aplicaciones Los datos persisten al ser desinstalada la App, excepto con getExternalFilesDir

Internal Storage External Storage

getFilesDir getCacheDir

getExternalStoragePublicDirectory (directorio público) getExternalFilesDir (directorio privado)

Dispositivo Dispositivo SD card USB+ + … +

Page 28: Android Superstar - Buenas Prácticas

ContentProvider

Almacenar y compartir datos

Permite proveer de información a otras Activities o aplicaciones (a través de exported=true) !Además, se puede restringir el acceso a los datos a través de permisos (existentes o nuevos) !Es una especie de API pública de acceso a datos a nuestra aplicación !URI + métodos: onCreate(), query(), insert(), update(), delete(), getType()

App

Content Provider

App externa 1

App externa 2

Page 29: Android Superstar - Buenas Prácticas

BroadcastReceiver

Almacenar y compartir datos

Cuando se quiere informar a otras activities o aplicaciones de cambios ocurridos en nuestra aplicación !Quien quiere recibir notificaciones debe registrarse !Quien quiere mandar notificaciones debe enviarlas al sistema

Service Sistema Android

BroadcastReceiver

sendBroadcast()

onReceive()

Page 30: Android Superstar - Buenas Prácticas

Mejor Receivers o Alarms que Services

Almacenar y compartir datos

Cuando se quiere informar a otras activities o aplicaciones de cambios ocurridos en nuestra aplicación !Las activities de nuestra aplicación o de terceros que se registren no deberán estar constantemente comprobando si han ocurrido cambios, sino que se les informará cuando estos ocurran

Page 31: Android Superstar - Buenas Prácticas

Preferencias

Almacenar y compartir datos

getSharedPreferences —> distintos archivos identificados por un nombre !getPreferences —> archivo por defecto

SharedPreferences preferencias = getSharedPreferences(“Prueba",Context.MODE_PRIVATE); ! SharedPreferences.Editor editor = preferencias.edit(); editor.putString("clave", “valor"); editor.commit();

/data/data/paquete/ shared_prefs/nombre.xml

<?xml version='1.0' encoding=‘utf-8' standalone='yes' ?> <map> <string name="clave">valor</string> … </map>

Page 32: Android Superstar - Buenas Prácticas

Base de datos

Almacenar y compartir datos

Acceder a la base de datos en un AsyncTask o IntentService —> siempre en background !SQLiteOpenHelper onCreate - crear tablas iniciales onUpgrade - actualizar base de datos tras cambios de una versión a otra getReadableDatabase - acceso a BD en modo lectura getWriteableDatabase) - acceso a BD en modo escritura !SQLiteDatabate (insert, update, delete, rawQuery, query) !Consultas —> query() + Projection para obtener únicamente las columnas deseadas !Los cursores son como las neveras, hay que cerrarlos después de usarlos!

Page 33: Android Superstar - Buenas Prácticas

Usabilidad y accesibilidad

contentDescription

Es un elemento de accesibilidad de los elementos gráficos !Permite que a través del Text To Speech (TTS) se reproduzca su valor para ayudar a entender el significado del elemento (por ejemplo, describe una imagen para ser entendida por gente con problemas de visión)

<ImageView android:layout_width="50dp" android:layout_height="match_parent" android:adjustViewBounds="true" android:padding=“5dp" android:contentDescription="@string/contentDescriptionInfo"! android:src="@drawable/info" />

Page 34: Android Superstar - Buenas Prácticas

Usabilidad y accesibilidad

Juego de focos: navegación entre elementos

Además de para accesibilidad, existentes elementos en dispositivos como trackballs y botones de flechas que permiten navegar entre elementos !Por ello es necesario indicar cual debe ser la navegación a través del foco: nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight

View

android:nextFocusUp

android:nextFocusDown

android:nextFocusRightandroid:nextFocusLeft

Page 35: Android Superstar - Buenas Prácticas

Usabilidad y accesibilidad

inputType, hint, imeOptions y windowSoftInputModeinputType especifica el tipo de teclado a mostrar: numérico, contraseña, etc. !hint mostrará un texto temporal hasta que el usuario introduzca otro !imeOptions mostrará la acción a realizar: done, search, go, etc. !windowSoftInputMode permite mostrar o no el teclado al crear la activity, además de indicar cómo se verá afectado el layout cuando se muestre el mismo: escalar, desplazar, etc.

Pan & Scan Resize

Page 36: Android Superstar - Buenas Prácticas

Otros

Lint

Es una herramienta muy importante !Nos ayudará a encontrar errores o mejoras a realizar sobre nuestro código

Page 37: Android Superstar - Buenas Prácticas

Otros

Monkey

Es una herramienta de testing muy útil !Permite realizar pruebas de interacción con los elementos gráficos de forma automática y aleatoria (como si un mono se pusiera a “toquitear” todo

$ adb shell monkey [options] <event-count>

$ adb shell monkey -p your.package.name -v 500

Las opciones permiten: - Indicar número de eventos a realizar - Indicar paquetes concretos a probar - Tipos de eventos y frecuencia de los mismos - Opciones de depuración !Y el mono trabaja por nosotros!

Page 38: Android Superstar - Buenas Prácticas

Otros

ProGuard

No debemos regalar nuestro código !Decompilar un APK es tremendamente sencillo !ProGuard nos permite añadir seguridad a nuestro código, ofuscándolo y dificultando que terceros puedan obtener nuestro código fuente a través del binario !ProGuard realmente: - Ofusca - Optimiza - Verifica !Ojo con Serializables

-dontwarn javax.swing.** -dontwarn javax.security.** !# Esto impide problemas con el javascript en caso de existencia de WebViews -keepclassmembers class fqcn.of.javascript.interface.for.webview { public *; } !# Esto impide problemas con el javascript en caso de existencia de WebViews -keepclassmembers class * { @android.webkit.JavascriptInterface <methods>; } # También podemos evitar la ofuscación de clases concretas de nuestro código -keep public class com.package.miapp.MiClase !-printmapping proguard.map -renamesourcefileattribute ProGuard -keepattributes SourceFile,LineNumberTable

Page 39: Android Superstar - Buenas Prácticas

Referencias

http://developer.android.com/develop/index.html

http://www.slideshare.net/jmpereirag/developing-android-the-movie

http://android-developers.blogspot.com.es/

Lectura obligatoria

Lectura recomendada

Lectura para recordar

Lectura divertida

http://blog.vogella.com/

http://commonsware.com/blog/Lectura del Gurú

Page 40: Android Superstar - Buenas Prácticas

Ignacio Muñoz Vicente @imunoz_

I wanna be anSuperstar!

Buenas prácticas en el desarrollo de aplicaciones para Android

Page 41: Android Superstar - Buenas Prácticas

EXTRA: JIT vs AOT

Dalvik (JIT) VS ART (AOT)

JIT (Just in Time) vs AOT (Ahead of Time) !En Dalvik se va compilando el código mientras de va ejecutando (se convierte el código DEX a código máquina) !En ART se compila y se convierte a código máquina en la instalación !Rapidez VS más tiempo de instalación y espacio de almacenamiento