Pemrograman Mobile
Lanjut
#3: AsyncTaskLoader
Muhamad Saad Nurul Ishlah, M.Comp.
Program Studi Sistem Informasi, Sekolah Vokasi,
Universitas Pakuan
Pembahasan
- Loaders
- AsyncTaskLoader
Loaders
Loader?
-
Menyediakan pemuatan data secara asinkronus
-
Terhubung kembali ke Activity setelah terjadi perubahan konfigurasi
-
Dapat memonitor perubahan pada sumber data dan mengirimkan data baru
-
Callback diimplementasikan di Activity
-
Terdapat banyak tipe loader:
-
AsyncTaskLoader
-
CursorLoader
-
Kenapa Menggunakan Loaders?
- Mengeksekusi operasi di luar thread UI
- LoaderManager menghandel perubahan konfigurasi untuk Anda
- Secara efisien diimplementasikan oleh framework
- Pengguna tidak perlu menunggu data dimuat
Apa itu LoaderManager?
- Mengatur fungsi-fungsi loader melalui callback
- Dapat mengatur multi-loader, misal:
- loader untuk basis data,
- loader untuk data AsyncTask,
- loader untuk data internet
- dll
Mendapatkan loader
- Menggunakan metode initLoader()
- Buat atau mulai sebuah loader, atau gunakan kembali yang sudah ada, termasuk datanya
- GUnakan metode restartLoader() untuk membersihkan data pada loader yang sudah ada
getLoaderManager().initLoader(Id, args, callback);
getLoaderManager().initLoader(0, null, this);
getSupportLoaderManager().initLoader(0, null, this);
AsyncTaskLoader
Overview AsyncTaskLoader
AsyncTask ke AsyncTaskLoader
AsyncTask
-
doInBackground()
-
onPostExecute()
AsyncTaskLoader
-
loadInBackground()
-
onLoadFinish()
Metode yang perlu ditimpa (Override)
Membuat Sebuah AsyncTaskLoader
-
Buat subkelas AsyncTaskLoader
-
Implementasikan constructor
-
Override loadInBackground()
-
Override onStartLoading()
Ketika restartLoader() atau initLoader dipanggil, LoaderManager akan memanggil callback onStartLoading().
- Cek untuk data yang di-cache
- Mulai observasi sumber data (jika diperlukan)
- Panggil forceLoad() untuk memuat data jika terdapat perubahan atau tidak terdapat data cache
public static class StringListLoader
extends AsyncTaskLoader<List<String>> {
public StringListLoader(Context context, String queryString) {
super(context);
mQueryString = queryString;
}
@Override
public List<String> loadInBackground() {
List<String> data = new ArrayList<String>;
// TODO: Muat data dari jaringan atau basis data
return data;
}
@Override
protected void onStartLoading() {
forceLoad();
}
}
Selanjutnya Apa?
Implementasikan callback loader di Activity
- onCreateLoader(): membuat dan mengembalikan loader baru untuk ID yang diberikan
- onLoadFinished(): dipanggil ketika loader yang sebelumnya dibuat telah selesai dimuat
- onLoaderReset(): dipanggil ketika loader yang sebelumnya sedang di-reset sehingga data tidak tersedia
public class MainActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBookInput = findViewById(R.id.bookInput);
mTitleText = findViewById(R.id.titleText);
mAuthorText = findViewById(R.id.authorText);
if (getSupportLoaderManager().getLoader(0) != null) {
getSupportLoaderManager().initLoader(0, null, this);
}
}
// onCreateLoader
@Override
public Loader<List<String>> onCreateLoader(int id, Bundle args) {
return new StringListLoader(this,args.getString("queryString"));
}
// Hasil dari pemanggilan metode loadInBackground() disampaikan ke
// metode onLoadFinished() ini, di mana Anda dapat menunjukkannya
// di sini
@Override
public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
mAdapter.setData(data);
}
// Hanya dipanggil ketika loader dimusnahkan
@Override
public void onLoaderReset(final LoaderList<String>> loader) {
// Biasanya dibiarkan kosong
}
...
}
Selanjutnya Apa?
Dapatkan loader dengan initLoader()
- Di Activity
- Gunakan pustaka support agar kompatibel dengan perangkat Android secara umum
public class MainActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBookInput = findViewById(R.id.bookInput);
mTitleText = findViewById(R.id.titleText);
mAuthorText = findViewById(R.id.authorText);
if (getSupportLoaderManager().getLoader(0) != null) {
getSupportLoaderManager().initLoader(0, null, this);
}
}
// onCreateLoader
@Override
public Loader<List<String>> onCreateLoader(int id, Bundle args) {
return new StringListLoader(this,args.getString("queryString"));
}
// Hasil dari pemanggilan metode loadInBackground() disampaikan ke
// metode onLoadFinished() ini, di mana Anda dapat menunjukkannya
// di sini
@Override
public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
mAdapter.setData(data);
}
// Hanya dipanggil ketika loader dimusnahkan
@Override
public void onLoaderReset(final LoaderList<String>> loader) {
// Biasanya dibiarkan kosong
}
...
}
Contoh Implementasi (Loader)
/*
* Kelas BookLoader.java
* Sumber: https://github.com/google-developer-training/android-fundamentals-apps-v2/blob/master/WhoWroteItLoader/app/src/main/java/com/example/android/whowroteitloader/BookLoader.java
*/
package com.example.android.whowroteitloader;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v4.content.AsyncTaskLoader;
public class BookLoader extends AsyncTaskLoader<String> {
private String mQueryString;
BookLoader(Context context, String queryString) {
super(context);
mQueryString = queryString;
}
@Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad();
}
@Nullable
@Override
public String loadInBackground() {
return NetworkUtils.getBookInfo(mQueryString);
}
}
Contoh Implementasi (Activity)
/*
* Kelas MainActivity.java
* Sumber: https://github.com/google-developer-training/android-fundamentals-apps-v2/blob/master/WhoWroteItLoader/app/src/main/java/com/example/android/whowroteitloader/MainActivity.java
*/
package com.example.android.whowroteitloader;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* The WhoWroteIt app queries the Book Search API for books based
* on a user's search. It uses an AsyncTask to run the search task in
* the background.
*/
public class MainActivity extends AppCompatActivity
implements LoaderManager.LoaderCallbacks<String> {
private EditText mBookInput;
private TextView mTitleText;
private TextView mAuthorText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBookInput = findViewById(R.id.bookInput);
mTitleText = findViewById(R.id.titleText);
mAuthorText = findViewById(R.id.authorText);
if (getSupportLoaderManager().getLoader(0) != null) {
getSupportLoaderManager().initLoader(0, null, this);
}
}
/**
* onClick handler for the "Search Books" button.
*
* @param view The view (Button) that was clicked.
*/
public void searchBooks(View view) {
// Get the search string from the input field.
String queryString = mBookInput.getText().toString();
// Hide the keyboard when the button is pushed.
InputMethodManager inputManager = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputManager != null) {
inputManager.hideSoftInputFromWindow(view.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
// Check the status of the network connection.
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = null;
if (connMgr != null) {
networkInfo = connMgr.getActiveNetworkInfo();
}
// If the network is available, connected, and the search field
// is not empty, start a BookLoader AsyncTask.
if (networkInfo != null && networkInfo.isConnected()
&& queryString.length() != 0) {
Bundle queryBundle = new Bundle();
queryBundle.putString("queryString", queryString);
getSupportLoaderManager().restartLoader(0, queryBundle, this);
mAuthorText.setText("");
mTitleText.setText(R.string.loading);
}
// Otherwise update the TextView to tell the user there is no
// connection, or no search term.
else {
if (queryString.length() == 0) {
mAuthorText.setText("");
mTitleText.setText(R.string.no_search_term);
} else {
mAuthorText.setText("");
mTitleText.setText(R.string.no_network);
}
}
}
@NonNull
@Override
public Loader<String> onCreateLoader(int id, @Nullable Bundle args) {
String queryString = "";
if (args != null) {
queryString = args.getString("queryString");
}
return new BookLoader(this, queryString);
}
@Override
public void onLoadFinished(@NonNull Loader<String> loader, String data) {
try {
// Convert the response into a JSON object.
JSONObject jsonObject = new JSONObject(data);
// Get the JSONArray of book items.
JSONArray itemsArray = jsonObject.getJSONArray("items");
// Initialize iterator and results fields.
int i = 0;
String title = null;
String authors = null;
// Look for results in the items array, exiting when both the
// title and author are found or when all items have been checked.
while (i < itemsArray.length() &&
(authors == null && title == null)) {
// Get the current item information.
JSONObject book = itemsArray.getJSONObject(i);
JSONObject volumeInfo = book.getJSONObject("volumeInfo");
// Try to get the author and title from the current item,
// catch if either field is empty and move on.
try {
title = volumeInfo.getString("title");
authors = volumeInfo.getString("authors");
} catch (JSONException e) {
e.printStackTrace();
}
// Move to the next item.
i++;
}
// If both are found, display the result.
if (title != null && authors != null) {
mTitleText.setText(title);
mAuthorText.setText(authors);
//mBookInput.setText("");
} else {
// If none are found, update the UI to show failed results.
mTitleText.setText(R.string.no_results);
mAuthorText.setText("");
}
} catch (Exception e) {
// If onPostExecute does not receive a proper JSON string,
// update the UI to show failed results.
mTitleText.setText(R.string.no_results);
mAuthorText.setText("");
e.printStackTrace();
}
}
@Override
public void onLoaderReset(@NonNull Loader<String> loader) {
// Do nothing. Required by interface.
}
}
Referensi
Referensi
-
Diterjemahkan dari slide Android Developer Fundamentasl V2: AsyncTask and AsyncTaskLoader
-
UI Thread Performance: Exceed the Android Speed Limit
-
Video Tutorial: https://www.youtube.com/watch?v=uKx0FuVriqA
Terima Kasih
PML3: AsyncTaskLoader
By M. Saad Nurul Ishlah
PML3: AsyncTaskLoader
- 308