En aquest tema, aprendrem com gestionar tasques en segon pla en una aplicació Android. Les tasques en segon pla són operacions que es realitzen fora del fil principal de la interfície d'usuari (UI), permetent que l'aplicació continuï sent responsiva mentre es duen a terme operacions que poden trigar temps, com ara descàrregues de xarxa, operacions de base de dades, o processament de dades.
Conceptes Clau
- Fil Principal (Main Thread): És el fil on s'executa la interfície d'usuari de l'aplicació. Qualsevol operació que trigui massa temps en aquest fil pot fer que l'aplicació sembli bloquejada.
- Tasques en Segon Pla: Operacions que es realitzen fora del fil principal per evitar bloquejar la UI.
- AsyncTask: Una classe antiga per gestionar tasques en segon pla, però que ja no es recomana per a noves aplicacions.
- Executors: Una API més moderna per gestionar fils en segon pla.
- WorkManager: Una API per gestionar tasques en segon pla que necessiten ser persistents i poden ser programades per a un moment específic.
Executors
Introducció
Els Executors proporcionen una manera fàcil de gestionar fils en segon pla. Utilitzen un grup de fils (thread pool) per executar tasques de manera eficient.
Exemple Pràctic
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class BackgroundTaskExample { public static void main(String[] args) { // Crear un executor amb un sol fil ExecutorService executor = Executors.newSingleThreadExecutor(); // Definir una tasca en segon pla Runnable backgroundTask = new Runnable() { @Override public void run() { // Codi de la tasca en segon pla System.out.println("Tasques en segon pla executant-se"); try { Thread.sleep(2000); // Simular una tasca que triga 2 segons } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Tasques en segon pla finalitzades"); } }; // Executar la tasca en segon pla executor.execute(backgroundTask); // Tancar l'executor executor.shutdown(); } }
Explicació
- ExecutorService: Creem un executor amb un sol fil.
- Runnable: Definim una tasca en segon pla que imprimeix missatges abans i després de dormir durant 2 segons.
- execute(): Executem la tasca en segon pla.
- shutdown(): Tanquem l'executor després de completar la tasca.
WorkManager
Introducció
WorkManager és una API robusta per gestionar tasques en segon pla que necessiten ser persistents i poden ser programades per a un moment específic. És ideal per a tasques que han de continuar fins i tot si l'aplicació es tanca o el dispositiu es reinicia.
Exemple Pràctic
Pas 1: Afegir la Dependència
Afegiu la següent dependència al vostre build.gradle
:
Pas 2: Crear una Classe Worker
import android.content.Context; import androidx.annotation.NonNull; import androidx.work.Worker; import androidx.work.WorkerParameters; public class MyWorker extends Worker { public MyWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { // Codi de la tasca en segon pla try { Thread.sleep(3000); // Simular una tasca que triga 3 segons } catch (InterruptedException e) { e.printStackTrace(); return Result.failure(); } return Result.success(); } }
Pas 3: Programar la Tasca
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Crear una sol·licitud de treball OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class).build(); // Programar la tasca WorkManager.getInstance(this).enqueue(workRequest); } }
Explicació
- Dependència: Afegim la dependència de WorkManager al nostre projecte.
- MyWorker: Creem una classe que extén
Worker
i implementa el mètodedoWork()
, on definim la tasca en segon pla. - OneTimeWorkRequest: Creem una sol·licitud de treball per executar la tasca una vegada.
- WorkManager: Programem la tasca utilitzant
WorkManager
.
Exercici Pràctic
Enunciat
Creeu una aplicació Android que descarregui una imatge d'una URL en segon pla i la mostri en una ImageView
quan la descàrrega hagi finalitzat.
Solució
Pas 1: Afegir Permisos
Afegiu el permís d'internet al vostre AndroidManifest.xml
:
Pas 2: Crear la Classe Worker
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.work.Worker; import androidx.work.WorkerParameters; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class DownloadImageWorker extends Worker { public DownloadImageWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { String imageUrl = getInputData().getString("image_url"); Bitmap bitmap = downloadImage(imageUrl); if (bitmap != null) { // Guardar la imatge en un lloc accessible per a l'UI ImageStorage.saveImage(getApplicationContext(), bitmap); return Result.success(); } else { return Result.failure(); } } private Bitmap downloadImage(String imageUrl) { try { URL url = new URL(imageUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.connect(); InputStream input = connection.getInputStream(); return BitmapFactory.decodeStream(input); } catch (Exception e) { e.printStackTrace(); return null; } } }
Pas 3: Crear una Classe per Guardar la Imatge
import android.content.Context; import android.graphics.Bitmap; import java.io.FileOutputStream; public class ImageStorage { public static void saveImage(Context context, Bitmap bitmap) { try { FileOutputStream fos = context.openFileOutput("downloaded_image.png", Context.MODE_PRIVATE); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.close(); } catch (Exception e) { e.printStackTrace(); } } public static Bitmap loadImage(Context context) { try { return BitmapFactory.decodeStream(context.openFileInput("downloaded_image.png")); } catch (Exception e) { e.printStackTrace(); return null; } } }
Pas 4: Programar la Tasca i Mostrar la Imatge
import androidx.appcompat.app.AppCompatActivity; import android.graphics.Bitmap; import android.os.Bundle; import android.widget.ImageView; import androidx.work.Data; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; import androidx.work.Worker; import androidx.work.WorkerParameters; public class MainActivity extends AppCompatActivity { private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.imageView); // Crear una sol·licitud de treball amb dades d'entrada Data inputData = new Data.Builder() .putString("image_url", "https://example.com/image.png") .build(); OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(DownloadImageWorker.class) .setInputData(inputData) .build(); // Programar la tasca WorkManager.getInstance(this).enqueue(workRequest); // Observar els resultats de la tasca WorkManager.getInstance(this).getWorkInfoByIdLiveData(workRequest.getId()) .observe(this, workInfo -> { if (workInfo != null && workInfo.getState().isFinished()) { // Carregar la imatge guardada i mostrar-la Bitmap bitmap = ImageStorage.loadImage(this); if (bitmap != null) { imageView.setImageBitmap(bitmap); } } }); } }
Explicació
- Permís d'Internet: Afegim el permís d'internet al manifest.
- DownloadImageWorker: Creem una classe
Worker
per descarregar la imatge en segon pla. - ImageStorage: Creem una classe per guardar i carregar la imatge descarregada.
- MainActivity: Programem la tasca de descàrrega i observem els resultats per mostrar la imatge quan la descàrrega hagi finalitzat.
Conclusió
En aquest tema, hem après com gestionar tasques en segon pla utilitzant Executors i WorkManager. Hem vist exemples pràctics de com implementar aquestes tècniques i hem creat una aplicació que descarrega una imatge en segon pla i la mostra a la interfície d'usuari. Les tasques en segon pla són essencials per mantenir la responsivitat de les aplicacions Android i proporcionar una millor experiència d'usuari.
Curs d'Android Studio
Mòdul 1: Introducció a Android Studio
- Introducció a Android Studio
- Configuració d'Android Studio
- Comprensió de la Interfície d'Android Studio
- Creació del teu Primer Projecte Android
Mòdul 2: Desenvolupament Bàsic d'Android
- Comprensió de l'Estructura del Projecte Android
- Introducció als Dissenys XML
- Components Bàsics de la Interfície d'Usuari
- Introducció a les Activitats
- Executar la teva Aplicació en un Emulador
Mòdul 3: Desenvolupament Intermedi d'Android
- Introducció als Intents
- Treballar amb Fragments
- Gestió de l'Entrada de l'Usuari
- Ús de RecyclerView
- Xarxes en Android
Mòdul 4: Desenvolupament Avançat d'Android
- Persistència de Dades amb SQLite
- Ús de Room per a la Gestió de Bases de Dades
- Components Avançats de la Interfície d'Usuari
- Vistes Personalitzades i Canvas
- Treballar amb Tasques en Segon Pla
Mòdul 5: Desenvolupament Professional d'Android
- Implementació de l'Arquitectura MVVM
- Injecció de Dependències amb Dagger
- Proves Unitàries i Proves de la Interfície d'Usuari
- Publicació de la teva Aplicació a Google Play
- Optimització del Rendiment