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

  1. 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.
  2. Tasques en Segon Pla: Operacions que es realitzen fora del fil principal per evitar bloquejar la UI.
  3. AsyncTask: Una classe antiga per gestionar tasques en segon pla, però que ja no es recomana per a noves aplicacions.
  4. Executors: Una API més moderna per gestionar fils en segon pla.
  5. 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ó

  1. ExecutorService: Creem un executor amb un sol fil.
  2. Runnable: Definim una tasca en segon pla que imprimeix missatges abans i després de dormir durant 2 segons.
  3. execute(): Executem la tasca en segon pla.
  4. 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:

dependencies {
    implementation "androidx.work:work-runtime:2.7.0"
}

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ó

  1. Dependència: Afegim la dependència de WorkManager al nostre projecte.
  2. MyWorker: Creem una classe que extén Worker i implementa el mètode doWork(), on definim la tasca en segon pla.
  3. OneTimeWorkRequest: Creem una sol·licitud de treball per executar la tasca una vegada.
  4. 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:

<uses-permission android:name="android.permission.INTERNET"/>

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ó

  1. Permís d'Internet: Afegim el permís d'internet al manifest.
  2. DownloadImageWorker: Creem una classe Worker per descarregar la imatge en segon pla.
  3. ImageStorage: Creem una classe per guardar i carregar la imatge descarregada.
  4. 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.

© Copyright 2024. Tots els drets reservats