2011-04-24 24 views
45

Recientemente escribí mi primera aplicación para Android, que tenía aproximadamente entre 8,000 y 10,000 líneas de código. Una cosa que continuamente obstaculizó mi uso de patrones de diseño normales fue el uso intensivo de llamadas asincrónicas de Android (apertura de diálogos, actividades, etc.). Debido a esto, mi código rápidamente comenzó a buscar "spaghetti", y finalmente comencé a sentir aversión al mirar ciertas clases.Mejores prácticas de programación asincrónica

¿Existen patrones de diseño específicos o metodologías de programación que son para sistemas como estos que cualquiera podría recomendar? ¿Hay alguna sugerencia para escribir código asíncrono manejable?

+3

Sin un ejemplo de lo que usted considera una estructura "spaghetti" forzada por la programación de eventos, será difícil que alguien le aconseje. – CommonsWare

+0

Un ejemplo de cómo realizar un seguimiento de los estados de programa condicionales al usar llamadas como showDialog()/onDialogCreate() cuando se combina con un oyente de botón dentro del cuadro de diálogo. Puede ser complicado gestionar el flujo. – Ryan

+0

Quizás no deba usar diálogos. :-) Los diálogos en Android deberían ser la excepción, no la regla. Un ejemplo: relativamente pocas aplicaciones web usan un diálogo modal (equivalentes de HTML), aunque ciertamente es posible con la biblioteca correcta. – CommonsWare

Respuesta

45
  • utilizar variables globales

Si no quiere estropear su código con simples Intent.putExtra() llamadas y manejar estas cosas para cada Activity único que tendrá que utilizar variables globales dentro de la aplicación . Extienda Application y almacene los datos que necesite mientras su aplicación esté activa. Para implementarlo realmente, use this excellent answer. Esto hará que las dependencias entre actividades desaparezcan. Por ejemplo, supongamos que necesita un "nombre de usuario" para su aplicación durante el ciclo de vida de la aplicación; esta es una excelente herramienta para eso. No necesita llamadas sucias Intent.putExtra().

  • Use estilos

Un error común al hacer la primera aplicación Android es que uno por lo general simplemente comenzar a escribir las vistas XML. Los archivos XML llegarán (sin problema y muy rápido) a muchas líneas de código. Aquí puede tener una solución donde solo usa el atributo style para implementar un comportamiento específico. Por ejemplo, considere este pedazo de código:

valores/styles.xml:

<style name="TitleText"> 
    <item name="android:layout_height">wrap_content</item> 
    <item name="android:layout_width">wrap_content</item> 
    <item name="android:textSize">18sp</item> 
    <item name="android:textColor">#000</item> 
    <item name="android:textStyle">bold</item> 
</style> 

diseño/main.xml:

Ahora, si usted tiene, digamos, dos TextView sy ambos deben tener el mismo comportamiento, haga que utilicen el estilo TitleText. Código de muestra:

<!--- ... --> 
<TextView 
    android:id="@+id/textview_one" 
    style="@style/TitleText" 
/> 

<TextView 
    android:id="@+id/textview_two" 
    style="@style/TitleText" 
/> 
<!--- ... --> 

Simple y no necesita duplicar el código. Si realmente desea profundizar en este tema en particular, consulte Layout Tricks: Creating Reusable UI Components.

  • utilizar cadenas

Este punto es corto, pero creo que es importante mencionar que. Otro error que pueden cometer los desarrolladores es omitir strings.xml y simplemente escribir mensajes de IU (y nombres de atributos) dentro del código (donde lo necesitará). Para hacer que su aplicación sea más fácil de mantener; solo defina mensajes y atributos en el archivo strings.xml.

  • crear y utilizar una clase de herramienta global

Cuando escribí mi primer métodos donde lo necesitaba aplicación que acabo de escribir (y duplicado). ¿El resultado? Una gran cantidad de métodos que tenían el mismo comportamiento entre varias actividades. Lo que aprendí es hacer una clase de herramienta. Por ejemplo, supongamos que debe realizar solicitudes web en todas sus actividades. En ese caso, omita definirlos dentro del Activity real y cree un método estático para ello.Código de ejemplo:

public final class Tools { 

    private Tools() { 
    } 

    public static final void sendData(String url, 
       String user, String pass) { 
     // URLConnections, HttpClients, etc... 
    } 

} 

Ahora, sólo puede utilizar este código de abajo en su Activity que necesita para enviar datos hacia un servidor:

Tools.sendData("www.www.www", "user", "pass"); 

Sin embargo, usted consigue el punto. Utilice este "patrón" donde lo necesite, le evitará estropear su código.

  • Let clases personalizadas definen el comportamiento en el que el usuario tiene que interactuar con la aplicación

Este es probablemente el punto más útil. Para definir "donde el usuario necesita interactuar con su aplicación" digamos que tiene un Menu, cuyo comportamiento es muy largo en términos de líneas, ¿por qué mantenemos los cálculos de Menu en la misma clase? Cada pequeño elemento hará que su clase Activity sea una pieza dolorosa de código más largo; su código se verá como "spaghetti". Por ejemplo, en lugar de tener algo como esto:

@Override 
public boolean onPrepareOptionsMenu(Menu menu) { 
    MenuItem item; 
    item = menu.findItem(R.id.menu_id_one); 
    if (aBooleanVariable) { 
     item.setEnabled(true); 
    } else { 
     item.setEnabled(false); 
    } 
    // More code... 
    return super.onPrepareOptionsMenu(menu); 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem i) { 
    // Code, calculations... 
    // ... 
    // ... 
    return super.onOptionsItemSelected(i); 
} 

rediseñarlo a algo como esto:

private MyCustomMenuInstance mMenuInstance; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState);   
    setContentView(R.layout.main); 

    mMenuInstance = new MyCustomMenuInstance(); 
} 

@Override 
public boolean onPrepareOptionsMenu(Menu menu) { 
    mMenuInstance.onPrepareOptionsMenu(menu); 
    return super.onPrepareOptionsMenu(menu); 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem i) { 
    mMenuInstance.onOptionsItemSelected(i); 
    return super.onOptionsItemSelected(i); 
} 

Por ejemplo, MyCustomMenuInstance:

public class MyCustomMenuInstance { 

    // Member fields.. 

    public MyCustomMenuInstance() { 
     // Init stuff. 
    } 

    public void onPrepareOptionsMenu(Menu menu) { 
     // Do things.. 
     // Maybe you want to modify a variable in the Activity 
     // class? Well, pass an instance as an argument and create 
     // a method for it in your Activity class. 
    } 

    public void onOptionsItemSelected(MenuItem i) { 
     // Do things.. 
     // Maybe you want to modify a variable in the Activity 
     // class? Well, pass an instance as an argument and create 
     // a method for it in your Activity class. 
    } 

} 

A ver dónde va esto. Puede aplicar esto a muchas cosas, p. onClick, onClickListener, onCreateOptionsMenu, la lista es larga. Para conocer más "mejores prácticas", puede ver algunas aplicaciones de muestra de Google here. Busque cómo han implementado las cosas de una manera agradable y correcta.

Última palabra; Mantenga limpio su código, nombre sus variables y métodos de una manera lógica y especialmente de manera correcta. Siempre, siempre entienda dónde se encuentra en su código, eso es muy importante.

+0

Para su clase de herramientas abstractas, no lo haga de esa manera. Composición sobre personas de herencia. Hágalo de esa manera en su lugar: http://en.wikipedia.org/wiki/Composition_over_inheritance –

+0

@Robert Massaioli: Esto tampoco es herencia, solo una clase de herramienta con métodos estáticos; disponible cuando lo necesite. – Wroclai

+0

Ah, sí, me confundiste porque la forma habitual en que dices que esta clase nunca debe ser instanciada o sub-clasificada es otorgarle un constructor privado. Si todos sus métodos son públicos estáticos, entonces puede llamar directamente desde cualquier lugar de todos modos. Me confundí con el uso de 'abstracto'. –

3

Si la manipulación de la interfaz de usuario es su mayor preocupación, entonces querrá dominar la codificación controlada por eventos. Las ideas detrás de la codificación basada en eventos están detrás de todos los sistemas modernos de IU, y son útiles en todo tipo de cosas (no solo en la IU).

La manera más fácil de pensarlo cuando aprendí fue simplemente tratar cada componente y evento como si fuera autónomo. Todo lo que debe preocuparse es el objeto del evento pasado a su método de evento. Si estás acostumbrado a escribir aplicaciones que se ejecutan básicamente de principio a fin, es un cambio de mentalidad, pero la práctica te llevará allí muy rápidamente.

6

Desde una perspectiva amateur, no espero que mi primer intento sea una aplicación limpia y lista para producción. Termino con spaghetti, fettucini e incluso código de ravioles a veces. En ese momento, trato de volver a pensar qué es lo que me gusta el máximo rendimiento del código, y la búsqueda de una mejor alternativa:

  • Repensar sus clases para describir mejor los objetos,
  • mantener el código en cada método al mínimo,
  • dependencias evitar las variables estáticas en cualquier lugar que puede,
  • hilos de uso para tareas costosas, no utilizarlos para procedimientos rápidos,
  • separar la interfaz de usuario de la lógica de aplicación (mantenerlo en sus clases en su lugar),
  • mantener campos privados en cualquier lugar se puede: será útil cuando se desea cambiar su clase,
  • iterar a través de éstos hasta que te gusta el código

Uno de los errores más comunes que he visto en Los métodos asíncronos usan una variable estática dentro de un ciclo que crea uno o más subprocesos, sin considerar que el valor puede cambiar en otro subproceso. ¡Evite la estática!

Como OceanBlue señala, no puede ser claro de esto que final static variables no crean ningún peligro, pero las variables estáticas públicas que el cambio puede . No es un problema con la estática en sí, sino con la idea de que tendrán un valor y luego descubrirán que el valor ha cambiado. Puede ser difícil detectar dónde estaba el problema. Los ejemplos típicos serían un contador de clics o un valor de temporizador, cuando podría haber hecho clic en más de una vista o más de un temporizador.

Espero que reciba sugerencias de personas con mucha más experiencia que yo. ¡Buena suerte!

+0

@Aleamdam: Usted enfatiza no usar estadísticas.Me gustaría saber cuál es su opinión sobre el uso de valores públicos estáticos finales. Básicamente, los valores de negocio que en lugar de hardcoding, uno podría poner en una clase separada, algo así como: MyBusinessDefs.java? – OceanBlue

+1

@OceanBlue lo que enfatizo no depender de variables públicas estáticas ** que pueden cambiar durante la ejecución de un hilo **. Por supuesto, las variables 'estáticas finales 'no plantean ese problema. De hecho, prefiero su uso porque no solo son fáciles de cambiar si es necesario, sino que también ayudan en la claridad de la lectura. Aclararé más ese punto en mi respuesta. – Aleadam

0

¿Qué ocurre con el uso del patrón de controlador de vista de modelo?

Al menos hay que aislar en el "modelo" (objeto o conjunto de objetos) todo el estado y su administración lógica, y tienen en una clase separada (tal vez la clase de actividad) todas las cosas relacionadas con las vistas, los oyentes, las devoluciones de llamada, ...)