• Uncategorized
  • 0

11.1B: Add a content provider to your database

Task 1. Download and run the base code

Praktik ini melanjutkan aplikasi WordListSQLInteractive dan MinimalistContentProvider yang telah Anda buat sebelumnya. Anda akan memperluas salin WordListSQLInteractive. Anda bisa memulai dari kode Anda sendiri atau mengunduh aplikasi.

Task 2. Add a Contract class to WordListSQLInteractive

Mulai dengan membuat kelas Contract yang mendefinisikan konstanta database publik, konstanta URI, dan tipe MIME. Anda akan menggunakan konstanta ini di semua kelas lainnya.

2.1 Add a Contract class

Tambahkan kelas final publik ke proyek Anda dan beri nama Contract.

Kelas Contract ini berisi semua informasi yang diperlukan aplikasi lain untuk menggunakan penyedia konten aplikasi Anda. Anda bisa memberi nama apa pun pada kelas ini, tetapi umumnya disebut sebagai “Contract”.

public final class Contract {}

Agar kelas Contract tidak dibuat instance-nya, tambahkan constructor pribadi yang kosong.

private Contract() {}

2.2 Move database constants into Contract

Pindahkan konstanta untuk database sehingga aplikasi lain perlu mengetahui di luar WordListOpenHelper ke dalam Contract dan membuatnya publik.

Pindahkan DATABASE_NAME dan buat menjadi publik.

public static final String DATABASE_NAME = "wordlist"; Buat kelas dalam WordList yang mengimplementasikan BaseColumns.
public static abstract class WordList implements BaseColumns {
}

Pindahkan nama WORD_LIST_TABLE, serta nama kolom KEY_IDdan KEY_WORD dari WordListOpenHelper ke dalam kelas WordList di Contract dan buat menjadi publik.

Kembali ke WordListOpenHelper dan tunggu agar Android Studio mengimpor konstanta dari Contract atau mengimpornya secara manual, jika Anda belum menyiapkan impor otomatis.

Gunakan File > Settings > Editor > General > Auto Importdi Windows

2.3 Define URI Constants

Deklarasikan skema URI untuk penyedia konten Anda.

  1. public static final int ALL_ITEMS = -2;
    public static final String COUNT = "count";
    
    public static final String AUTHORITY =
           "com.android.example.wordlistsqlwithcontentprovider.provider";
    
    public static final String CONTENT_PATH = "words";
    
    public static final Uri CONTENT_URI =
           Uri.parse("content://" + AUTHORITY + "/" + CONTENT_PATH);
    public static final Uri ROW_COUNT_URI =
           Uri.parse("content://" + AUTHORITY + "/" + CONTENT_PATH + "/" + COUNT);
    

2.4 Declare the MIME types

  1. Deklarasikan tipe MIME untuk satu atau beberapa respons catatan:
    static final String SINGLE_RECORD_MIME_TYPE =
       "vnd.android.cursor.item/vnd.com.example.provider.words";
    static final String MULTIPLE_RECORDS_MIME_TYPE =
       "vnd.android.cursor.item/vnd.com.example.provider.words";
    
  2. Jalankan aplikasi Anda. Aplikasi harus berjalan dan tampak dan bertindak persis seperti sebelum Anda mengubahnya.

Task 3. Create a Content Provider

Dalam tugas ini, Anda akan membuat penyedia konten, mengimplementasikan metode kuerinya, dan mengaitkannya dengan WordListAdapter dan WordListOpenHelper.

3.1 Create a WordListContentProvider class

  1. Buat kelas baru yang memperluas ContentProvider dan beri nama WordListContentProvider.
  2. Di Android Studio, klik bola lampu merah, pilih “Implement methods”, dan klik OK untuk mengimplementasikan semua metode yang dicantumkan.
  3. Tentukan TAG log.
  4. Deklarasikan UriMatcher.

private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

5. Deklarasikan variabel kelas WordListOpenHelper, mDB.

private WordListOpenHelper mDB;

 

6. Deklarasikan kode untuk URI matcher sebagai konstanta.

private static final int URI_ALL_ITEMS_CODE = 10;
private static final int URI_ONE_ITEM_CODE = 20;
private static final int URI_COUNT_CODE = 30;

 

7. Ubah metode onCreate() untuk

  • menginsialisasi mDB dengan WordListOpenHelper,
  • memanggil metode initializeUriMatching() yang akan Anda buat nanti,
  • dan mengembalikan true.
    @Override
    public boolean onCreate() {
       mDB = new WordListOpenHelper(getContext());
       initializeUriMatching();
       return true;
    }

8. Buat metode void pribadi initializeUriMatching().

9. Di initializeUriMatching(), tambahkan URI ke matcher untuk mendapatkan semua item, satu item, dan jumlahnya.

3.2 Implement WordListContentProvider.query()

Gunakan MiniContentProvider sebagai template untuk mengimplementasikan metode query().

  1. Modifikasi WordListContentProvider.query().
  2. Gunakan pernyataan Switch untuk kode yang dikembalikan oleh sUriMatcher.
  3. Untuk URI_ALL_ITEMS_CODE, URI_ONE_ITEM_CODE, URI_COUNT_CODE, panggil yang sesuai di WordListOpenHelper (mDB).

solusi :

3.3 Fix WordListOpenHelper.query() to return a Cursor and handle returning all items

Karena penyedia konten bekerja dengan kursor, Anda bisa menyederhanakan metode WordListOpenHelper.query() untuk mengembalikan kursor.

  1. Tambahkan kode dengan sebuah kueri untuk mengembalikan semua item dari database untuk menangani kasus cursor = mDB.query(ALL_ITEMS) dari pernyataan Switch di atas.
  2. Sederhanakan WordListOpenHelper.query() agar mengembalikan kursor.

solusi :

3.4 Fix WordListOpenHelper.count() to return a Cursor

Karena penyedia konten bekerja dengan kursor, Anda juga harus mengubah metode WordListOpenHelper.count() untuk mengembalikan kursor.

Gunakan MatrixCursor yang merupakan kursor dari baris dan kolom yang bisa diubah.

  1. Buat MatrixCursor menggunakan Contract.CONTENT_PATH.
  2. Di dalam blok try, dapatkan jumlah dan tambahkan sebagai baris ke kursor.
  3. Kembalikan kursor.

solusi :

3.5 Fix WordListAdapter.onBindViewHolder() to use a content resolver

Selanjutnya, Anda akan memperbaiki WordListAdapter.onBindViewHolder() untuk menggunakan resolver konten, bukan memanggil WordListOpenHelper secara langsung.

  1. Di WordListAdapter, hapus variabel mDB, karena Anda tidak lagi secara langsung mengacu ke database. Ini menampilkan kesalahan di Android Studio yang akan memandu perubahan Anda selanjutnya.
  2. Di constructor, hapus penetapan ke mDB.
  3. Refactor > Change tanda tangan constructor dan hapus parameter db.
  4. Tambahkan variabel instance untuk parameter kueri karena akan digunakan lebih dari sekali.

private String queryUri = Contract.CONTENT_URI.toString(); // base uri
private static final String[] projection = new String[] {Contract.CONTENT_PATH}; //table
private String selectionClause = null;
private String selectionArgs[] = null;
private String sortOrder = "ASC";

5. Di onBindViewHolder(), hapus dua baris kode pertama.

  • WordItem current – mDB.query(position);
  • holder.wordItemView.setText(current.getWord());

6. Define an empty String variable named word.

7. Definisikan variabel integer yang disebut sebagai id dan setel menjadi -1.

8.Buat resolver konten dengan parameter kueri yang ditetapkan dan simpan hasilnya di sebuah Cursor yang disebut sebagai cursor.

  1. String word = "";
    int id = -1;
    
    Cursor cursor = mContext.getContentResolver().query(Uri.parse(
                        queryUri), null, null, null, sortOrder);
    

9. Sebagai ganti hanya mengirimkan WordItem, WordListAdapter.onBindViewHolder() harus melakukan pekerjaan ekstra yaitu mengekstrak kata dari kursor yang dikembalikan oleh resolver konten.

  • Jika kursor yang dikembalikan berisi data, ekstrak kata dan setel teks holder tampilan.
  • Ekstrak id-nya, karena Anda akan memerlukannya untuk listener klik.
  • Tutup kursor. Ingatlah bahwa Anda tidak menutup kursor di WordListOpenHelper.query(), karena Anda telah mengembalikannya.
  • Tangani jika ada kejadian tanpa data di kursor.
  • Implementasikan sumber daya string apa pun yang direferensikan.
if (cursor != null) {
      if (cursor.moveToPosition(position)) {
            int indexWord = cursor.getColumnIndex(Contract.WordList.KEY_WORD);
            word = cursor.getString(indexWord);
            holder.wordItemView.setText(word);
            int indexId = cursor.getColumnIndex(Contract.WordList.KEY_ID);
            id = cursor.getInt(indexId);
       } else {
            holder.wordItemView.setText(R.string.error_no_word);
       }

       cursor.close();

} else {
       Log.e (TAG, "onBindViewHolder: Cursor is null.");
}

10. Perbaiki parameter untuk listener klik untuk dua tombol:

  • current.getId() ⇒ id
  • current.getWord() ⇒ word

Listener klik yang diperbarui untuk tombol DELETE tampak seperti ini:

@Override
public void onClick(View v) {
selectionArgs = new String[]{Integer.toString(id)};
int deleted = mContext.getContentResolver().delete(
    Contract.CONTENT_URI, Contract.CONTENT_PATH,selectionArgs);
 if (deleted > 0) {
     // Need both calls
     notifyItemRemoved(h.getAdapterPosition());
     notifyItemRangeChanged(
             h.getAdapterPosition(), getItemCount());
 } else {
      Log.d (TAG, mContext.getString(R.string.not_deleted) + deleted);
 }
}

11. Ganti panggilan ke mDB.delete(id) di callback tombol DELETE dengan panggilan resolver konten yang akan dihapus.

selectionArgs = new String[]{Integer.toString(id)};
int deleted = mContext.getContentResolver().delete(
               Contract.CONTENT_URI, Contract.CONTENT_PATH, selectionArgs);

 

 

3.6 Change WordListAdapter.getItemCount() to use a content resolver

Sebagai ganti meminta hitungan dari database, getItemCount() harus tersambung ke resolver konten dan meminta hitungan. Di Contract, Anda mendefinisikan URI untuk mendapatkan hitungan tersebut:

public static final String COUNT = "count";
public static final Uri ROW_COUNT_URI =
       Uri.parse("content://" + AUTHORITY + "/" + CONTENT_PATH + "/" + COUNT

Ubah WordListAdaptergetItemCount() ke:

  • Menggunakan kueri resolver konten untuk mendapatkan hitungan item
  • Menggunakan ROW_COUNT_URI di kueri Anda
  • Hitungan adalah tipe integer dan merupakan elemen pertama Cursor yang dikembalikan
  • Mengekstrak count dari kursor dan mengembalikannya
  • Mengembalikan -1
  • Menutup kursor

Gunakan kode yang baru saja Anda tulis untuk onBindViewHolder sebagai panduan

solusi :

 

3.7 Add the content provider to the Android Manifest

  1. Jalankan aplikasi Anda.
  2. Periksa logcat untuk melihat penyebab kesalahan (yang sangat umum).
  3. Tambahkan penyedia konten ke Manifes Android di dalam tag <application>.
    <provider
       android:name=".WordListContentProvider"  android:authorities="com.android.example.wordlistsqlwithcontentprovider.provider">
    </provider>
    
  4. Jalankan aplikasi Anda.

 

3.8 What’s next?

  • Anda telah mengimplementasikan penyedia konten dan metode query()-nya.
  • Anda telah mengikuti kesalahan untuk memperbarui metode di kelas WordListOpenHelper dan WordListAdapter untuk bekerja dengan penyedia konten.
  • Saat Anda menjalankan aplikasi, panggilan metode masuk ke penyedia konten.
  • Untuk operasi penyisipan, penghapusan, dan pembaruan, aplikasi Anda masih memanggil WordListOpenHelper.

Dengan infrastruktur yang telah Anda bangun, Anda tidak perlu lagi berupaya keras mengimplementasikan metode yang tersisa.

Task 4. Implement Content Provider methods

4.1 getType()

Metode getType() dipanggil oleh aplikasi lain yang ingin menggunakan penyedia konten ini, untuk melihat jenis data seperti apa yang dikembalikan oleh aplikasi Anda.

Gunakan pernyataan Switch untuk mengembalikan tipe MIME yang sesuai.

  • Tipe MIME dicantumkan dalam Contract.
  • SINGLE_RECORD_MIME_TYPE adalah untuk URI_ALL_ITEMS_CODE
  • MULTIPLE_RECORDS_MIME_TYPE adalah untuk URI_ONE_ITEM_CODE

soulsi :

 

4.2 Call the content provider to insert and update words in MainActivity

Untuk memperbaiki operasi penyisipan, MainActivity().onActivityResult perlu memanggil penyedia konten, bukan database untuk menyisipkan dan memperbarui kata.

  1. Di MainActivity, hapus deklarasi mDB dan pembuatan instance-nya.

Di OnActivityResult()

Menyisipkan:

  1. Jika panjang kata tidak nol, buat variabel ContentValues bernama “values” dan tambahkan kata yang dimasukkan oleh pengguna ke dalamnya menggunakan string “word” sebagai kunci.
  2. Ganti mDB.insert(word); dengan permintaan insert ke sebuah resolver konten.

Memperbarui:

  1. Ganti mDB.update(id, word); dengan permintaan update ke sebuah resolver konten.

solusi :

 

4.3 Implement insert() in the content provider

Metode insert() di penyedia konten merupakan pass-through. Jadi, Anda

  1. memanggil metode insert() OpenHelper,
  2. mengonversi long id yang dikembalikan ke sebuah URI konten ke item yang disisipkan,
  3. dan mengembalikan URI tersebut.

Android Studio melaporkan kesalahan untuk parameter values, yang akan Anda perbaiki di langkah selanjutnya.

solusi :

4.4 Fix insert() in WordListOpenHelper

Android Studio melaporkan kesalahan untuk parameter values.

  1. Buka WordListOpenHelper. Metode insert() ditulis untuk mengambil parameter String.
  2. Ubah parameter menjadi tipe ContentValues.
  3. Hapus deklarasi dan penetapan values di isi metode.

4.5 Implement update() in the content provider

Perbaiki metode update dengan cara yang sama seperti yang Anda pakai untuk memperbaiki metode insert.

  1. Di WordListContentProvider, implementasikan update(), yang merupakan satu baris kode yang meneruskan id dan word sebagai argumen.
    return mDB.update(parseInt(selectionArgs[0]),
    values.getAsString(Contract.WordList.KEY_WORD));
    
  2. Anda tidak perlu membuat perubahan apa pun untuk memperbarui WordListOpenHelper.

 

4.6 Implement delete() in the content provider

Di WordListContentProvider, implementasikan metode delete() dengan memanggil metode delete() di WordListOpenHelper dengan di kata untuk dihapus.

return mDB.delete(parseInt(selectionArgs[0]));

4.7 Run your app

 

You may also like...

Leave a Reply

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