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

  1. Buat subkelas AsyncTaskLoader 

  2. Implementasikan constructor

  3. Override loadInBackground()

  4. 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

Terima Kasih

PML3: AsyncTaskLoader

By M. Saad Nurul Ishlah

PML3: AsyncTaskLoader

  • 308