Руководство Android AsyncTaskLoader
View more Tutorials:
AsyncTaskLoader используется для выполнения асинхронной задачи (asynchronous task) в фоновом режиме приложения, поэтому во время выполнения задачи пользователь так же может взаимодействовать с приложением. После того как задача выполнена, результат будет обновлен на интерфейсе.
AsyncTaskLoader выполняет такие же функции как AsyncTask, но AsyncTaskLoader лучше из-за следующих причин:
AsyncTask и AsyncTaskLoader имеет другое поведение когда когда конфигурация устройства меняется, например, пользователь поворачивает устройство, Activity может быть разрушен (destroy) и создан заново(re-create). И тогда:
- AsyncTask будет перевыполнен (re-executed) и новый Thread будет создан, старый Thread становится отдельным и неуправляемым.
- AsyncTaskLoader буден использован повторно (re-used) на основе Loader ID зарегистрированный с LoaderManager до этого. Таким образом он предотвращает дупликацию задач в фоновом режиме и избегает создания бесполезных задач.
Android AsyncTaskLoader Javadocs:Смотрите так же:
В данном примере мы будем использовать AsyncTaskLoader чтобы скачать список UserAccount и отобразить его на интерфейсе. Эти данные могут быть получены из URL или из базы данных. Данная задача выполняется в фоновом режиме приложения, поэтому в процессе выполнения задачи пользователь все так же может взаимодействовать с приложением.

На Android Studio создайте новый project:
- File > New > New Project > Empty Activity
- Name: AsyncTaskLoaderExample
- Package name: org.o7planning.asynctaskloaderexample
- Language: Java
Интерфейс приложения:

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; } }