El tutor de nuestro curso online de Desarrollo de Aplicaciones para Android, Víctor Ramírez Las,…
Proyecto ejemplo: tareas en segundo plano en Aplicación Android
3.
Proyecto ejemplo: tareas en segundo plano en Aplicación Android
Vamos a ver un ejemplo práctico de implementación de tareas background en Android, con un proyecto en el que gestionaremos varios hilos en segundo plano mediante el uso de la clase AsyncTask.
La aplicación que vamos a describir paso a paso, se encargará de simular tres barras de progreso , actualizando tanto el aspecto visual de la barra como el porcentaje asociado a la misma. Cada barra estará controlada por un hilo secundario en el que se modificarán los tiempo de duración para comprobar que dichos procesos no bloquean el hilo principal de la aplicación.
Como es habitual, podrás descargar todo el código del proyecto al final de este tutorial (usuarios Premium)
Descripción de la Aplicación
Aunque mostraremos la aplicación en funcionamiento en un próximo video, para hacernos una idea podemos ver la pantalla principal de la app en la imagen de abajo.
Como se aprecia, mostrará un botón junto con tres barras de progreso. Al ser pulsado dicho botón («Tareas Segundo Plano»), se mostrará el proceso de avance de los diferentes componentes visuales:
A continuación, enumeramos los elementos necesarios para el desarrollo del proyecto que vamos a denominar «TareasSegundoPlano»:
- Clase
MainActivity
, que herede de la clase baseActivity
, y cuya principal característica será la de lanzar las tareas que se ejecutarán en segundo plano, mostrando el progreso de las mismas. - Clase
PorcentajeDos
, que herede de la claseAsyncTask
, y que gestionará una barra de progreso en segundo plano, actualizando el porcentaje cada 200 milésimas (1/5 segundo). - Clase
PorcentajeCinco
, que herede de la claseAsyncTask
, y que gestionará una barra de progreso en segundo plano, actualizando el porcentaje cada 500 milésimas (1/2 segundo). - Clase
PorcentajeDiez
, que herede de la claseAsyncTask
, y que gestionará una barra de progreso en segundo plano, actualizando el porcentaje cada 1000 milésimas (1 segundo). - Layout
activity_main.xml
, formado por un layout de tipoRelativeLayout
, y que a su vez contiene unTableLayout
, que dispondrá en diferentes filas tanto el botón como las barras de progreso implementadas.
Versiones utilizadas: para realizar este proyecto se ha utilizado la versión de Android Studio 2.1.2 y la Versión SDK de compilación: API 23 para Android 6.0 Marshmallow.
Estructura del proyecto
Siguiendo con la lógica general de presentación del proyecto, en la siguiente imagen se visualizará la estructura de elementos que intervienen, todo desde la vista Android:
Descripción del código fuente
Continuando con la descripción del proyecto, en las siguientes líneas explicamos el código de las clases y fichero de layout que componen el mismo.
TareasSegundoPlano\app\src\main\java\com\academiaandroid\tareassegundoplano\MainActivity.class
Activity que mostrará un control de tipo Button y tres controles de tipo ProgressBar
(control que indicará de manera gráfica el progreso de una tarea), que comenzarán su progreso una vez el usuario pulse el botón definido:
1 2 3 4 5 6 7 8 9 10 |
package com.academiaandroid.tareassegundoplano; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends Activity { |
Se declara una variable de tipo Button
a nivel de clase:
1 2 |
private Button btnTareaSegundoPlano; |
Posteriormente, dentro del método onCreate()
, se asigna a la variable de tipo Button
, el identificador único del control definido a nivel de layout, mediante el método findViewById()
:
1 2 3 4 5 6 7 8 9 10 |
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnTareaSegundoPlano = (Button)findViewById(R.id.btnTareaSegundoPlano); [...] |
Finalmente, y todavía dentro del método onCreate()
, se invoca al método setOnClickListener()
del objeto btnTareaSegundoPlano
, encargado de controlar la pulsación del botón y crear una instancia de la clase PorcentajeDos()
.
P
rocesará una de las tareas en segundo plano y recibe como argumento de entrada el contexto de la aplicación.
Además como se puede apreciar, invoca al método execute()
, para la realización de la tarea:
1 2 3 4 5 6 7 8 9 10 11 12 |
[...] btnTareaSegundoPlano.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new PorcentajeDos(MainActivity.this).execute("Carga Finalizada X2"); } }); } } |
TareasSegundoPlano\app\src\main\java\com\academiaandroid\tareassegundoplano\PorcentajeDos.class
Clase encargada de gestionar el porcentaje de una barra de progreso, en segundo plano, actualizando dicho componente cada 200 milésimas.
Esta clase heredará de la clase base Asynctask<String, Integer, String> que como se comenta en apartados anteriores, define tres tipos genéricos, que en este ejemplo se trata de:
- String: parámetro que se recibirá como entrada para la tarea en el método doInBackground(Params), y que mostrará el texto «Carga Finalizada X2»
- Integer: parámetro que actualizará el hilo principal mediante el avance de la barra de progreso
- String: que será el resultado devuelto por el procesamiento en segundo plano, en este caso el texto pasado como parámetro desde el método
execute()
:
1 2 3 |
public class PorcentajeDos extends AsyncTask<String, Integer, String> { |
MainActivity
(establecerá el contexto de la aplicación para mostrar los diferentes mensajes por pantalla), una variable de tipo ProgressBar
(permitirá actualizar la barra de progreso), y una variable de tipo TextView
(actualizará el porcentaje actual):
1 2 3 4 |
private MainActivity context; private ProgressBar progressBarDos; private TextView tvDos; |
1 2 3 4 5 |
public PorcentajeDos(MainActivity context) { this.context = context; } |
1 2 3 4 5 6 7 |
@Override protected void onPreExecute() { super.onPreExecute(); Toast.makeText(context, "Progreso X2", Toast.LENGTH_LONG).show(); } |
doInBackground()
, procesará el parámetro de entrada (en nuestro caso sólo será un mensaje que se muestre al finalizar la tarea) y actualizará el progreso del componente ProgressBar. Una de las particularidades del código situado dentro de este método, consiste en invocar al método sleep()
de la clase Thread
, para realizar una pausa de 200 milésimas en cada iteración (así se simula correctamente el funcionamiento de una barra de progreso):
1 2 3 4 |
@Override protected String doInBackground(String... params) { |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for(int i = 0; i <= 100; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } publishProgress(i); } return String.valueOf(params[0]); } |
TextView
su identificador único (control definido en el layout de la Activity principal). Como se puede apreciar, se invoca al método findViewById()
desde el contexto de la aplicación definido en el constructor de esta clase. Finalmente se actualizará el valor de la variable TextView
por cada ciclo del método doInBackground()
:
1 2 3 4 5 6 7 8 9 10 |
@Override protected void onProgressUpdate (Integer... valores) { super.onProgressUpdate(valores); progressBarDos = (ProgressBar)context.findViewById(R.id.progressBarDos); progressBarDos.setProgress(valores[0]); tvDos = (TextView)context.findViewById(R.id.tvDos); tvDos.setText(valores[0] + "%"); } |
PorcentajeCinco
, para ejecutar dicha tarea en segundo plano:
1 2 3 4 5 6 7 8 9 |
@Override protected void onPostExecute(String s) { super.onPostExecute(s); Toast.makeText(context, s,Toast.LENGTH_LONG).show(); new PorcentajeCinco(context).execute("Carga Finalizada X5"); } } |
Nota: Se utiliza la clase PorcentajeDos como ejemplo para describir el código fuente, ya que el resto de clases (PorcentajeCinco y PorcentajeDiez) tiene una estructura similar, salvo en el texto que se mostrará al lanzar y finalizar el hilo, como la frecuencia de actualización de la barra de progreso (parámetro del método sleep() dentro de doInBackground() ).
TareasSegundoPlano\app\src\main\res\layout\activity_main.xml
Layout activity_main.xml
que estará formado por un TableLayout
, que establece la disposición de los elementos ordenados en filas, en las que se definen un control de tipo Button
, y tres controles de tipo ProgressBar
para las diferentes tareas que serán lanzadas por el usuario:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.tareassegundoplano.MainActivity"> <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="50dp"> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Tarea Segundo Plano" android:id="@+id/btnTareaSegundoPlano" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="50dp" android:id="@+id/progressBarDos" android:layout_toRightOf="@+id/progressBarCinco" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:id="@+id/tvDos" android:layout_column="2" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="50dp" android:id="@+id/progressBarCinco" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:id="@+id/tvCinco" android:layout_column="2" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="50dp" android:id="@+id/progressBarDiez" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:id="@+id/tvDiez" android:layout_column="2" /> </TableRow> </TableLayout> </RelativeLayout> |
Descarga del proyecto
En este botón puedes descargar todo el proyecto:
Download