devstory

Le Tutoriel de Android AsyncTaskLoader

  1. Android AsyncTaskLoader
  2. Exemple d'AsyncTaskLoader

1. Android AsyncTaskLoader

AsyncTaskLoader est utilisé pour exécuter une tâche asynchrone (asynchronous task) dans l'arrière-plan de l'application pour que l'utilisateur puisse interagir avec l'application pendant le processus. Dès que la tâche est achevée, le résultat est mis à jour dans l'interface.
AsyncTaskLoader exécute les mêmes fonctions qu'AsyncTask, mais AsyncTaskLoader est plus pratique pour les raisons suivantes:
AsyncTaskAsyncTaskLoader ont deux comportements différents quand la configuration de l'appareil change, par exemple, si l'utilisateur fait pivoter l'écran, Activity est probablement détruite (destroy) et re-créée (re-create). Et dans ce cas-là:
  • AsyncTask est ré-exécuté (re-executed) et un nouveau Thread est créé, l'ancien Thread est séparé et incontrôlé.
  • AsyncTaskLoader est ré-utilisé (re-used) en fonction de Loader ID ayant été enregistré auprès de LoaderManager. En conséquence, cela empêche la duplication des tâches d'arrières-plan et évite la création de tâches inutiles.

2. Exemple d'AsyncTaskLoader

Dans cet exemple, j'utilise AsyncTaskLoader pour télécharger la liste des UserAccount(s) et les afficher sur l'interface. Ces données peuvent être récupérées à partir d'une URL ou d'une base de données. Cette tâche est réalisée en arrière-plan de l'application, donc pendant le processus, l'utilisateur peut toujours interagir avec l'application.
Dans Android Studio, créer un nouveau projet:
  • File > New > New Project > Empty Activity
    • Name: AsyncTaskLoaderExample
    • Package name: org.o7planning.asynctaskloaderexample
    • Language: Java
L'interface de l'application:
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button_load"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="Load Data"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button_cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="Cancel"
        app:layout_constraintStart_toEndOf="@+id/button_load"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        app:layout_constraintStart_toEndOf="@+id/button_cancel"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:layout_marginBottom="16dp"
        android:background="#F3FAED"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button_load" />

</androidx.constraintlayout.widget.ConstraintLayout>
UserAccountTaskLoader.java
package org.o7planning.asynctaskloaderexample;

import android.content.Context;
import android.os.SystemClock;

import androidx.loader.content.AsyncTaskLoader;

import java.util.ArrayList;
import java.util.List;

public class UserAccountTaskLoader extends AsyncTaskLoader<List<UserAccount>> {

    private String param1;
    private String param2;

    public UserAccountTaskLoader(Context context, String param1, String param2) {
        super(context);
        this.param1 = param1;
        this.param2 = param2;
    }

    @Override
    public List<UserAccount> loadInBackground() {
        // Do something, for example:
        // - Download data from URL and parse it info Java object.
        // - Query data from Database into Java object.

        List<UserAccount> list = new ArrayList<UserAccount>();
        list.add(new UserAccount("tom", "tom@example.com", "Tom"));
        list.add(new UserAccount("jerry", "jerry@example.com", "Jerry"));
        list.add(new UserAccount("donald", "donald@example.com", "Donald"));

        SystemClock.sleep(2000); // 2 Seconds.

        return list;
    }
}
MainActivity.java
package org.o7planning.asynctaskloaderexample;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.util.List;

public class MainActivity extends AppCompatActivity //
        implements LoaderManager.LoaderCallbacks<List<UserAccount>>,
                   Loader.OnLoadCanceledListener<List<UserAccount>> {

    private static final String LOG_TAG = "AndroidExample";
    private static final int LOADER_ID_USERACCOUNT = 10000;

    private Button buttonLoad;
    private Button buttonCancel;
    private ProgressBar progressBar;
    private TextView textView;

    private static final String KEY_PARAM1 = "SomeKey1";
    private static final String KEY_PARAM2 = "SomeKey2";

    private LoaderManager loaderManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.buttonLoad = (Button) this.findViewById(R.id.button_load);
        this.buttonCancel = (Button) this.findViewById(R.id.button_cancel);
        this.progressBar = (ProgressBar) this.findViewById(R.id.progressBar);
        this.textView = (TextView) this.findViewById(R.id.textView);

        // Hide ProgressBar.
        this.progressBar.setVisibility(View.GONE);
        this.buttonCancel.setEnabled(false);

        this.buttonLoad.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clickButtonLoad();
            }
        });

        this.buttonCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clickButtonCancel();
            }
        });

        this.loaderManager = LoaderManager.getInstance(this);
    }

    // User click on "Load Data" button.
    private void clickButtonLoad() {
        this.textView.setText("");
        Log.i(LOG_TAG, "loadUserAccount");
        LoaderManager.LoaderCallbacks<List<UserAccount>> loaderCallbacks = this;

        // Arguments:
        Bundle args = new Bundle();
        args.putString(KEY_PARAM1, "Some value1");
        args.putString(KEY_PARAM2, "Some value2");

        // You can pass a null args to a Loader
        Loader<List<UserAccount>> loader =  this.loaderManager.initLoader(LOADER_ID_USERACCOUNT, args, loaderCallbacks);
        try {
            loader.registerOnLoadCanceledListener(this); // Loader.OnLoadCanceledListener
        } catch(IllegalStateException e) {
            // There is already a listener registered
        }
        loader.forceLoad(); // Start Loading..
    }

    // User click on "Cancel" button.
    private void clickButtonCancel() {
        Log.i(LOG_TAG, "cancelLoadUserAccount");
        Loader<List<UserAccount>> loader = this.loaderManager.getLoader(LOADER_ID_USERACCOUNT);
        if(loader != null)  {
            boolean cancelled = loader.cancelLoad();
        }
    }

    // Implements method of LoaderManager.LoaderCallbacks
    @NonNull
    @Override
    public Loader<List<UserAccount>> onCreateLoader(int id, @Nullable Bundle args) {
        Log.i(LOG_TAG, "onCreateLoader");

        this.progressBar.setVisibility(View.VISIBLE); // To show

        if(id == LOADER_ID_USERACCOUNT) {
            this.buttonLoad.setEnabled(false);
            this.buttonCancel.setEnabled(true);
            // Parameters:
            String param1 = (String) args.get(KEY_PARAM1);
            String param2 = (String) args.get(KEY_PARAM2);
            // Return a Loader.
            return new UserAccountTaskLoader(MainActivity.this, param1, param2);
        }
        throw new RuntimeException("TODO..");
    }

    // Implements method of LoaderManager.LoaderCallbacks
    @Override
    public void onLoadFinished(@NonNull Loader<List<UserAccount>> loader, List<UserAccount> data) {
        Log.i(LOG_TAG, "onLoadFinished");

        if(loader.getId() == LOADER_ID_USERACCOUNT) {
            // Destroy a Loader by ID.
            this.loaderManager.destroyLoader(loader.getId());

            StringBuilder sb = new StringBuilder();

            for(UserAccount userAccount: data)  {
                sb.append("Username:").append(userAccount.getUserName()).append("\t") //
                        .append("Email:").append(userAccount.getEmail()).append("\n");
            }
            this.textView.setText(sb.toString());
            // Hide ProgressBar.
            this.progressBar.setVisibility(View.GONE);
            this.buttonLoad.setEnabled(true);
            this.buttonCancel.setEnabled(false);
        }
    }

    // Implements method of LoaderManager.LoaderCallbacks
    @Override
    public void onLoaderReset(@NonNull Loader<List<UserAccount>> loader) {
        Log.i(LOG_TAG, "onLoaderReset");

        this.textView.setText("");
    }

    // Implements method of Loader.OnLoadCanceledListener
    @Override
    public void onLoadCanceled(@NonNull Loader<List<UserAccount>> loader) {
        Log.i(LOG_TAG, "onLoadCanceled");

        if(loader.getId() == LOADER_ID_USERACCOUNT) {
            // Destroy a Loader by ID.
            this.loaderManager.destroyLoader(loader.getId());

            this.progressBar.setVisibility(View.GONE); // To hide
            this.buttonLoad.setEnabled(true);
            this.buttonCancel.setEnabled(false);
        }
    }
}
UserAccount.java
package org.o7planning.asynctaskloaderexample;

public class UserAccount {

    private String userName;
    private String email;
    private String fullName;

    public UserAccount(String userName, String email, String fullName) {
        this.userName = userName;
        this.email = email;
        this.fullName = fullName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

}

Tutoriels de programmation Android

Show More