• Uncategorized
  • 0

7.2: Connect to the Internet with AsyncTask and AsyncTaskLoader

Task 1. Explore the Books API

1.1 Send a Books API Request

  1. Buka Google APIs Explorer (bisa ditemukan di https://developers.google.com/apis-explorer/).
  2. Klik Books API.
  3. Temukan (Ctrl-F atau Cmd-Fbooks.volumes.list dan klik nama fungsi tersebut. Anda seharusnya bisa melihat laman web yang mencantumkan berbagai parameter fungsi API Books yang melakukan penelusuran buku.
  4. Dalam bidang q masukkan nama buku, atau sebagain nama buku. Parameter q adalah satu-satunya bidang yang diwajibkan.
  5. Gunakan bidang maxResults dan printType untuk membatasi hasil ke 10 buku yang cocok yang dicetak. Bidang maxResults mengambil nilai integer yang membatasi jumlah hasil per kueri. Bidang printType mengambil satu dari tiga argumen string: all, yang tidak membatasi hasil menurut tipe sama sekali; books, yang hanya memberikan hasil buku dalam bentuk cetak; dan magazines yang memberikan hasil majalah saja.
  6. Pastikan switch “Authorize requests using OAuth 2.0” di bagian atas formulir dinonaktifkan. Klik Execute without OAuth di bagian bawah formulir.
  7. Gulir ke bawah untuk melihat Permintaan dan Respons.

Bidang Request adalah contoh Uniform Resource Identifier (URI). URI adalah string yang memberikan nama atau menemukan sumber daya tertentu. URL adalah tipe URI tertentu untuk mengidentifikasi dan menemukan sumber daya web. Untuk API Books, permintaannya adalah URL yang berisi penelusuran sebagai parameter (mengikuti parameter q).

1.2 Analyze the Books API Response

 

Di bagian bawah laman Anda bisa melihat Respons terhadap kueri. Respons menggunakan format JSON, yang merupakan format umum untuk respons kueri API. Dalam laman web API Explorer, kode JSON diformat dengan baik agar dapat dibaca oleh manusia. Dalam aplikasi Anda, repons JSON akan dikembalikan dari layanan API sebagai string tunggal, dan Anda perlu melakukan parsing pada string tersebut untuk mengesktrak informasi yang diperlukan.

  1. Dalam bagian Respons, temukan nilai untuk kunci “title”. Perhatikan bahwa hasil ini memiliki nilai dan kunci tunggal.
  2. Termukan nilai untuk kunci “authors”. Perhatikan bahwa kunci ini berisi larik nilai.
  3. Dalam praktik ini Anda hanya akan mengembalikan judul dan penulis item pertama.

Task 2. Create the “Who Wrote It?” App

2.1 Create the project and user interface

  1. Buat proyek aplikasi bernama Who Wrote it? dengan satu aktivitas, menggunakan Template Empty Activity.
  2. Tambahkan elemen UI berikut di dalam file XML, menggunakan LinearLayout vertikal sebagai tampilan root—tampilan yang berisi semua tampilan lain di dalam file XML layout. Pastikan LinearLayout menggunakan android:orientation="vertical":

    Tampilan

    Atribut

    Nilai

    TextView

    android:layout_width

    android:layout_height

    android:id

    android:text

    android:textAppearance

    wrap_content

    wrap_content

    @+id/instructions

    @string/instructions

    @style/TextAppearance.AppCompat.Title

    EditText

    android:layout_width

    android:layout_height

    android:id

    android:inputType

    android:hint

    match_parent

    wrap_content

    @+id/bookInput

    text

    @string/input_hint

    Button

    android:layout_width

    android:layout_height

    android:id

    android:text

    android:onClick

    wrap_content

    wrap_content

    @+id/searchButton

    @string/button_text

    searchBooks

    TextView

    android:layout_width

    android:layout_height

    android:id

    android:textAppearance

    wrap_content

    wrap_content

    @+id/titleText

    @style/TextAppearance.AppCompat.Headline

    TextView

    android:layout_width

    android:layout_height

    android:id

    android:textAppearance

    wrap_content

    wrap_content

    @+id/authorText

    @style/TextAppearance.AppCompat.Headline

  3. Dalam file strings.xml, tambahkan sumber daya string berikut ini:
    <string name="instructions">Enter a book name, or part of a
    book name, or just some text from a book to find
    the full book title and who wrote the book!</string>
    <string name="button_text">Search Books</string>
    <string name="input_hint">Enter a Book Title</string>
    
  4. Buat metode bernama searchBooks() dalam MainActivity.java untuk menangani tindakan tombol onClick. Seperti pada semua metode onClick, yang satu ini memerlukan Viewsebagai parameter.

2.2 Set up the Main Activity

Untuk menanyakan API Books, Anda perlu mendapatkan masukan pengguna dari EditText.

  1. Dalam MainActivity.java, buat variabel anggota untuk EditText, TextView penulis dan TextView judul.
  2. Inisialisasi variabel ini dalam onCreate().
  3. Dalam metode searchBooks(), dapatkan teks dari widget EditText dan konversikan ke String, menetapkannya ke variabel string.
    String queryString = mBookInput.getText().toString();
    
    

2.3 Create an empty AsyncTask

Sekarang Anda siap untuk terhubung ke internet dan menggunakan Book Search REST API. Konektivitas jaringan terkadang lamban atau mengalami penundaan. Hal ini bisa menyebabkan aplikasi menjadi tidak menentu dan lambat, jadi sebaiknya Anda tidak membuat koneksi jaringan pada thread UI.

Gunakan AsyncTask untuk membuat koneksi jaringan:

Buat kelas Java baru bernama FetchBook dalam aplikasi/java yang diperluas AsyncTask. AsyncTask memerlukan tiga argumen:

  • Parameter masukan.
  • Indikator kemajuan.
  • Jenis hasil.

2.4 Create the NetworkUtils class and build the URI

  1. Buat kelas Java baru bernama NetworkUtils dengan mengeklik File > New > Java Class dan hanya mengisi bidang “Name”.
  2. Buat variabel LOG_TAG unik untuk digunakan di semua kelas NetworkUtils untuk membuat catatan log:
    private static final String LOG_TAG = NetworkUtils.class.getSimpleName();
    
  3. Buat metode statis baru bernama getBookInfo() yang mengambil String sebagai parameter (yang akan menjadi istilah penelusuran) dan mengembalikan String (respons String JSON dari API yang Anda periksa sebelumnya).
    static String getBookInfo(String queryString){}
    
  4. Buat dua variabel lokal berikut dalam getBookInfo() yang akan dibutuhkan nanti untuk membantu menyambungkan dan membaca data yang datang.
    HttpURLConnection urlConnection = null;
    BufferedReader reader = null;
    
  5. Buat variabel lokal lain di akhir getBookInfo() untuk memasukkan respons mentah dari kueri dan mengembalikannya:

    String bookJSONString = null;
    return bookJSONString;
  6. Buat konstanta anggota berikut dalam kelas NetworkUtils:
    private static final String BOOK_BASE_URL =  "https://www.googleapis.com/books/v1/volumes?"; // Base URI for the Books API
    private static final String QUERY_PARAM = "q"; // Parameter for the search string
    private static final String MAX_RESULTS = "maxResults"; // Parameter that limits search results
    private static final String PRINT_TYPE = "printType";   // Parameter to filter by print type
    
  7. Buat blok try/catch/finally skeleton dalamgetBookInfo(). Di sinilah Anda akan membuat permintaan HTTP. Kode untuk membangun URI dan mengeluarkan kueri akan masuk ke dalam blok try.
  8. Bangun URI permintaan dalam blok try:
    //Build up your query URI, limiting results to 10 items and printed books
    Uri builtURI = Uri.parse(BOOK_BASE_URL).buildUpon()
           .appendQueryParameter(QUERY_PARAM, queryString)
           .appendQueryParameter(MAX_RESULTS, "10")
           .appendQueryParameter(PRINT_TYPE, "books")
           .build();
    
  9. Konversi URI ke URL:
    URL requestURL = new URL(builtURI.toString());

2.5 Make the Request

  1. Dalam blok try metode getBookInfo(), buka koneksi URL dan buat permintaan.
    urlConnection = (HttpURLConnection) requestURL.openConnection();
    urlConnection.setRequestMethod("GET");
    urlConnection.connect();
    
  2. Baca respons menggunakan InputStream dan StringBuffer, lalu konversikan ke String:
    InputStream inputStream = urlConnection.getInputStream();
    StringBuffer buffer = new StringBuffer();
    if (inputStream == null) {
       // Nothing to do.
       return null;
    }
    reader = new BufferedReader(new InputStreamReader(inputStream));
    String line;
    while ((line = reader.readLine()) != null) {
       /* Since it's JSON, adding a newline isn't necessary (it won't affect
          parsing) but it does make debugging a *lot* easier if you print out the
          completed buffer for debugging. */
       buffer.append(line + "\n");
    }
    if (buffer.length() == 0) {
       // Stream was empty.  No point in parsing.
       return null;
    }
    bookJSONString = buffer.toString();
    
  3. Tutup blok try dan log pengecualiannya dalam blok catch.
    catch (IOException e) {
       e.printStackTrace();
       return null;
    }
    
  4. Tutup kedua urlConnection dan variabel pembaca dalam blok finally:

    finally {
       if (urlConnection != null) {
           urlConnection.disconnect();
       }
       if (reader != null) {
           try {
               reader.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
    }

    5. Log nilai variabel bookJSONString sebelum mengembalikannya. Sekarang Anda sudah selesai dengan metode getBookInfo().

     Log.d(LOG_TAG, bookJSONString);
    

    6. Dalam metode AsyncTask doInBackground(), panggil metode getBookInfo(), meneruskan istilah penelusuran yang Anda dapatkan dari argumen params yang diteruskan oleh sistem (ini adalah nilai pertama dalam larik params). Kembalikan hasil dari metode ini dalam metode doInBackground():

    return NetworkUtils.getBookInfo(params[0]);
    

    7. Sekarang setelah AsyncTask disiapkan, Anda perlu meluncurkannya dari MainActivity menggunakan metode execute(). Tambahkan kode berikut ke metode searchBooks() dalam MainActivity.java untuk meluncurkan AsyncTask:

    new FetchBook(mTitleText, mAuthorText).execute(mQueryString);
    

    8.Jalankan aplikasi Anda. Eksekusi penelusuran. Aplikasi Anda akan crash. Lihat Log untuk memeriksa apa yang menyebabkan kesalahan. Anda seharusnya melihat baris berikut:

    Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)
    

    Kesalahan ini menunjukkan bahwa Anda belum menyertakan izin untuk mengakses internet dalam file AndroidManifest.xml. Terhubung ke internet menimbulkan masalah keamanan baru, karena itulah aplikasi Anda tidak memiliki konektivitas secara default. Anda harus menambahkan izin secara manual dalam bentuk tag <uses-permission>; dalam AndroidManifest.xml.

    
    

 

2.6 Add the Internet permissions

  1. Buka file AndroidManifest.xml.
  2. Semua izin aplikasi harus diletakkan dalam file AndroidManifest.xml di luar tag <application>;. Anda harus memastikan untuk mengikuti urutan tempat tag didefinisikan dalam AndroidManifest.xml.
  3. Tambahkan tag xml berikut di luar tag <application>:
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
  4. Bangun dan jalankan aplikasi Anda lagi. Menjalankan kueri seharusnya menghasilkan string JSON dicetak ke Log.

2.7 Parse the JSON string

Untuk melakukan parsing pada data JSON dan menangani pengecualian yang mungkin, lakukan hal berikut:

  1. Dalam onPostExecute(), tambahkan blok try/catch di bawag panggilan ke super.
  2. Gunakan kelas JSON Java bawaan (JSONObject dan JSONArray) untuk mendapatkan larik JSON item hasil dalam blok try.
    JSONObject jsonObject = new JSONObject(s);
    JSONArray itemsArray = jsonObject.getJSONArray("items");
    
  3. Iterasi melalui itemsArray, memeriksa judul dan informasi penulis setiap buku. Jika keduanya bukan null, keluar dari loop dan perbarui UI; jika tidak, terus periksa daftarnya. Dengan cara ini, hanya entri dengan judul dan penulis yang akan ditampilkan.

    //Iterate through the results
    for(int i = 0; i<itemsArray.length(); i++){
       JSONObject book = itemsArray.getJSONObject(i); //Get the current item
       String title=null;
       String authors=null;
       JSONObject volumeInfo = book.getJSONObject("volumeInfo");
    
       try {
           title = volumeInfo.getString("title");
           authors = volumeInfo.getString("authors");
       } catch (Exception e){
           e.printStackTrace();
       }
    
       //If both a title and author exist, update the TextViews and return
       if (title != null && authors != null){
           mTitleText.setText(title);
           mAuthorText.setText(authors);
           return;
       }
    }
    
  4. Jika tidak ada hasil yang memenuhi kriteria memiliki penulis dan judul yang valid, setel TextView judul untuk membaca “No Results Found”, dan hapus TextView authors.
  5. Dalam blok catch, cetak kesalahan ke log, setel TextView judul ke “No Results Found”, dan hapus TextView authors.

Task 3. Implement UI Best Practices

Anda sekarang memiliki aplikasi yang berfungsi dan menggunakan API Books untuk mengeksekusi penelusuran buku. Tetapi, ada beberapa hal yang tidak berjalan seperti yang diharapkan:

  • Saat pengguna mengeklik Search Books, keyboard tidak muncul, dan tidak ada indikasi bagi pengguna bahwa kueri sebenarnya sedang dieksekusi.
  • Jika tidak ada koneksi jaringan, atau bidang penelusuran kosong, aplikasi masih mencoba menanyakan API dan gagal tanpa memperbarui UI dengan benar.
  • Jika Anda memutar layar selama kueri, AsyncTask akan terputus koneksinya dari Aktivitas, dan tidak dapat memperbarui UI dengan hasilnya.

3.1 Hide the Keyboard and Update the TextView

  1. Menambahkan kode berikut ke metode searchBooks() untuk menyembunyikan keyboard saat tombol ditekan:
    InputMethodManager inputManager = (InputMethodManager)
                         getSystemService(Context.INPUT_METHOD_SERVICE);
    inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
                         InputMethodManager.HIDE_NOT_ALWAYS);
    
  2. Menambahkan satu baris kode di bawah panggilan untuk mengeksekusi tugas FetchBook yang mengubah TextView judul untuk menbaca “Loading…” dan menghapus TextView penulis.
  3. Mengekstrak sumber daya String.

3.2 Manage the network state and the empty search field case

Kapan pun aplikasi menggunakan jaringan, aplikasi itu perlu menangani kemungkinan koneksi jaringan tidak tersedia. Sebelum mencoba terhubung ke jaringan dalam AsyncTask atau AsyncTaskLoader, aplikasi harus memeriksa status koneksi jaringan.

  1. Modifikasi metode searchBooks() untuk memeriksa kedua koneksi jaringan dan apakah ada teks dalam bidang penelusuran sebelum mengeksekusi tugas FetchBook.
  2. Perbarui UI dalam kasus tidak ada koneksi internet atau tidak ada teks dalam bidang penelusuran. Tampilkan penyebab kesalahan dalam TextView.

Task 4. Migrate to AsyncTaskLoader

Saat menggunakan AsyncTask, AsyncTask tidak bisa memperbarui UI jika perubahan konfigurasi terjadi saat tugas latar belakang sedang berjalan. Untuk mengatasi situasi ini, Android SDK menyediakan serangkaian kelas bernama loader yang didesain secara spesifik untuk memuat data ke dalam UI secara asinkron.

Dalam tugas ini Anda akan menggunakan loader spesifik bernama AsyncTaskLoader. AsyncTaskLoader adalah subkelas abstrak Loader dan menggunakan AsyncTask untuk memuat data di latar belakang dengan efisien.

Loader menyediakan banyak fungsionalitas tambahan, bukan hanya untuk menjalankan tugas dan menghubungkan kembali ke Aktivitas. Misalnya, Anda bisa melampirkan loader ke sumber data dan membuatnya secara otomatis memperbarui elemen UI saat data dasarnya berubah. Loader juga bisa diprogram untuk melanjutkan memuat jika terganggu.

Mengimplementasikan Loader memerlukan komponen berikut:

 

4.1 Create an AsyncTaskLoader

  1. Salin proyek WhoWroteIt, untuk mempertahankan hasil dari praktik sebelumnya. Ganti nama proyek yang disalin menjadi WhoWroteItLoader.
  2. Buat kelas baru dalam direktori Java bernama BookLoader.

4.2 Modify MainActivity

Sekarang Anda harus mengimplementasikan Callback Loaderdalam MainActivity untuk menangani hasil dari metode loadInBackground()AsyncTaskLoader.

  1. Tambahkan implementasi LoaderManager.LoaderCallbacks ke deklarasi kelas Aktivitas Utama, yang berparameter dengan tipe String:
    public class MainActivity extends AppCompatActivity
                    implements LoaderManager.LoaderCallbacks<String>{
    
  2. Implementasikan metode yang diperlukan:onCreateLoader(), onLoadFinished(), onLoaderReset(). Letakkan kursor teks pada baris tanda tangan kelas dan masukkan Alt + Enter (Option + Enter di Mac). Pastikan semua metode dipilih.

Loader menggunakan kelas Bundle untuk meneruskan informasi dari aktivitas memanggil ke LoaderCallbacks. Anda bisa menambahkan data primitif ke bundel dengan metode putType()yang tepat.

Untuk memulai loader, Anda memiliki dua opsi:

  • initLoader(): Metode ini membuat loader baru jika belum ada dan bergerak dalam Bundel argumen. Jika loader ada, Aktivitas memanggil akan dikaitkan kembali dengannya tanpa memperbarui Bundel.
  • restartLoader(): Metode ini sama dengan initLoader() kecuali jika metode ini menemukan loader yang sudah ada, metode ini akan memusnahkan dan membuat ulang loader dengan Bundel yang baru.

Kedua metode didefinisikan dalam LoaderManager, yang mengelola semua instance Loader yang digunakan dalam Aktivitas (atau Fragmen). Setiap Aktivitas memiliki satu instance LoaderManager yang bertanggung jawab terhadap siklus hidup dan Loader yang dikelolanya.

 Untuk melakukannya, Anda perlu mengedit metode onClick untuk tombol itu.

  1. Dalam metode searchBooks(), yang merupakan metode onClick untuk tombol tersebut, ganti panggilan untuk mengeksekusi tugas FetchBook dengan panggilan untuk restartLoader(), yang meneruskan string kueri yang Anda dapatkan dari EditText dalam Bundel:

    Bundle queryBundle = new Bundle();
    queryBundle.putString("queryString", queryString);
    getSupportLoaderManager().restartLoader(0, queryBundle,this);
    

    Metode restartLoader() mengambil tiga argumen:

    • Loader id (berguna jika Anda mengimplementasikan lebih dari satu loader dalam aktivitas).
    • Argumen Bundle (tempat data yang diperlukan oleh loader disimpan).
    • Instance LoaderCallbacks yang Anda implementasikan dalam aktivitas. Jika ingin loader membawa hasil ke MainActivity, tetapkan this sebagai argumen ketiga.
  2. Periksa metode Override dalam kelas LoaderCallbacks. Metode ini adalah:

    • onCreateLoader(): Dipanggil saat Anda membuat instance Loader.
    • onLoadFinished(): Dipanggil ketika tugas loader sudah selesai. Ini adalah tempat di mana Anda menambahkan kode untuk memperbarui UI dengan hasilnya.
    • onLoaderReset(): Menghapus sumber daya yang tersisa.

Implementasikan onCreateLoader()

  1. Dalam onCreateLoader(), kembalikan instance kelas BookLoader, meneruskan queryString yang didapatkan dari Bundel argumen:
    return new BookLoader(this, args.getString("queryString"));
    

Implementasikan onLoadFinished()

  1. Perbarui onLoadFinished() untuk memproses hasil, yang merupakan respons String JSON mentah dari API Books.
    1. Salin kode dari onPostExecute() dalam kelas FetchBook ke to onLoadFinished() dalam MainActivity, dengan mengecualikan panggilan ke super.onPostExecute().
    2. Ganti argumen ke konstruktor JSONObject dengan data String yang diteruskan.
  2. Jalankan aplikasi Anda.

    Anda seharusnya memiliki fungsionalitas yang sama seperti sebelumnya, hanya saja sekarang di dalam Loader! Satu hal yang masih tidak berfungsi. Saat perangkat diputar, data View hilang. Ini karena saat Aktivitas dibuat (atau dibuat ulang), Aktivitas tidak tahu bahwa ada loader yang sedang berjalan. Metode initLoader() dibutuhkan dalam onCreate() dari MainActivity untuk menghubungkan ulang loader.

  3. Tambahkan kode berikut di onCreate() untuk menghubungkan ulang ke Loader jika sudah ada:

    if(getSupportLoaderManager().getLoader(0)!=null){
       getSupportLoaderManager().initLoader(0,null,this);
    }
    
    Catatan: Jika loader ada, inisialisasikan loader. Anda hanya perlu mengaitkan kembali loader ke Aktivitas jika kueri sudah dieksekusi. Dalam status awal aplikasi, data tidak dimuat sehingga tidak ada yang perlu dipertahankan.
  4. Jalankan aplikasi lagi dan putar perangkat. LoaderManager sekarang mempertahankan data di semua konfigurasi perangkat!

  5. Hapus kelas FetchBook karena sudah tidak digunakan lagi.

 

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *