codestory

Die Anleitung zu Android AsyncTaskLoader

  1. Android AsyncTaskLoader
  2. Das Beispiel vom AsyncTaskLoader

1. Android AsyncTaskLoader

AsyncTaskLoader wird verwendet, um eine asynchrone Aufgabe im Hintergrund der Anwendung auszuführen, sodass der Benutzer während dieses Vorgangs auch mit der Anwendung interagieren kann. Sobald die Aufgabe abgeschlossen wird, wird das Ergebnis auf die Interface aktualisiert.
AsyncTaskLoader führt dieselben Funktionen wie AsyncTask aus. Aber AsyncTaskLoader ist aus den folgenden Gründen besser:
AsyncTask und AsyncTaskLoader haben das unterschiedliche Verhalten wenn sich die Konfiguration des Geräts ändert. Wenn der Benutzer bzw. den Gerätebildschirm dreht, kann die Aktivität zerstört und neu erstellt werden. In diesem Fall:
  • AsyncTask wird wieder ausgeführt (re-executed) und ein neues Thread wird erstellt. Das alte Thread wird getrennt und unkontrolliert werden.
  • AsyncTaskLoader wird basierend auf Loader ID wiederverwendet, die zuvor beim LoaderManager registriert wurde. Dadurch wird die Verdoppelung von Hintergrundaufgaben verhindert und die Erstellung nutzloser Aufgaben vermieden.

2. Das Beispiel vom AsyncTaskLoader

In diesem Beispiel verwende ich AsyncTaskLoader, um eine Liste von UserAccount zu laden und in der Interface anzuzeigen. Die Daten können von einer URL oder aus einer Datenbank abgerufen werden. Diese Aufgabe wird im Hintergrund der Anwendung implementiert, sodass der Benutzer während dieses Vorgangs wahrscheinlich immer noch mit der Anwendung interagiert.
Auf Android Studio erstellen Sie ein neues Projekt:
  • File > New > New Project > Empty Activity
    • Name: AsyncTaskLoaderExample
    • Package name: org.o7planning.asynctaskloaderexample
    • Language: Java
Die Interface der Anwendung:
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;
    }

}

Anleitungen Android

Show More