11.1A: Mengimplementasikan Penyedia Konten Minimalis

Daftar Isi:

Penyedia konten adalah komponen yang secara aman mengelola akses ke repositori data bersama. Penyedia konten menyediakan antarmuka yang konsisten bagi aplikasi untuk mengakses data bersama. Aplikasi tidak mengakses penyedia secara langsung, tetapi menggunakan objek content resolver yang menyediakan antarmuka ke dan mengelola koneksi dengan penyedia konten.

Penyedia konten berguna karena:

  • Aplikasi tidak bisa membagikan data di Android—kecuali melalui penyedia konten.
  • Penyedia konten mengizinkan beberapa aplikasi untuk mengakses, menggunakan, dan memodifikasi sumber data tunggal dengan aman. Contoh: Kontak, skor game, kamus pemeriksa ejaan.
  • Anda bisa menetapkan tingkat kontrol akses (izin) untuk penyedia konten Anda.
  • Anda bisa menyimpan data secara terpisah dari aplikasi. Dengan memiliki penyedia konten, Anda bisa mengubah bagaimana data disimpan tanpa perlu mengubah antarmuka pengguna. Misalnya,Anda bisa membangun prototipe menggunakan data tiruan, lalu menggunakan database SQL untuk aplikasi yang nyata. Anda bahkan bisa menyimpan sebagian data Anda di awan dan sebagian data secara lokal, dan antarmuka pengguna tetap sama untuk aplikasi Anda.
  • Arsitektur ini memisahkan data dari antarmuka pengguna, sehingga tim development bisa bekerja secara independen pada aplikasi yang berhadapan dengna klien dan komponen sisi-server aplikasi Anda. Untuk aplikasi yang kompleks dan besar, antarmuka pengguna dan layanan data bisa dikembangkan oleh tim yang berbeda. Mereka bahkan bisa merupakan aplikasi yang terpisah. Bahkan aplikasi dengan penyedia konten tidak harus memiliki antarmuka pengguna.
  • Anda bisa menggunakan CursorLoader dan kelas lain yang diharapkan untuk berinteraksi dengan penyedia konten.
    Catatan: Jika aplikasi Anda tidak berbagi data dengan aplikasi lain, aplikasi Anda tidak memerlukan penyedia konten. Akan tetapi, karena penyedia konten secara jelas memisahkan implementasi backend Anda dari antarmuka pengguna, penyedia konten juga bisa berguna untuk merencanakan aplikasi yang lebih kompleks.

Diagram berikut merangkum bagian-bagian arsitektur penyedia konten. Arsitektur Penyedia Konten

Data: Aplikasi yang membuat penyedia konten memiliki data dan menentukan izin apa yang dimiliki aplikasi lain untuk bekerja dengan data.

Data sering kali disimpan dalam database SQLite, tetapi tidak wajib. Umumnya, data disediakan untuk penyedia konten sebagai tabel, mirip seperti tabel database, setiap baris mewakili satu entri dan setiap kolom mewakili atribut untuk entri tersebut. Misalnya, setiap baris dalam database kontak berisi satu entri dan entri tersebut bisa memiliki kolom untuk alamat email dan nomor telepon.

ContentProvider: Penyedia konten menyediakan antarmuka publik yang aman ke data, sehingga aplikasi lain bisa mengakses data dengan izin yang sesuai.

ContentResolver: Digunakan oleh Aktivitas untuk mengirimkan kueri ke penyedia konten. Content resolver mengembalikan data sebagai objek Cursor yang kemudian bisa digunakan, misalnya, oleh sebuah adaptor, untuk menampilkan data.

Kelas Contract (tidak diperlihatkan): Contract adalah kelas publik yang mengekspos informasi penting tentang penyedia konten ke aplikasi lain. Ini biasanya menyertakan URI untuk mengakses data, konstanta penting, dan struktur data yang akan dikembalikan.

Aplikasi mengirimkan permintaan ke penyedia konten menggunakan Uniform Resource Identifier atau URI konten. URI konten untuk penyedia konten memiliki bentuk umum berikut:

scheme://authority/path-to-data/dataset-name

  • skema (untuk URI konten, ini selalu content://)
  • authority (merepresentasikan domain, dan untuk penyedia materi biasanya berakhiran .provider)
  • path (merepresentasikan jalur ke data)
  • ID (secara unik mengidentifikasi rangkaian data untuk ditelusuri; misalnya nama file atau nama tabel)

URI berikut bisa digunakan untuk meminta semua entri di tabel "words":

content://com.android.example.wordcontentprovider.provider/words

Merancang skema URI adalah topik tersendiri dan tidak dicakup dalam kursus ini.

Content Resolver:Objek ContentResolver menyediakan metode query(), insert(), update(), dan delete() untuk mengakses data dari penyedia konten dan mengelola semua interaksi dengan penyedia konten untuk Anda. Dalam kebanyakan situasi, Anda cukup menggunakan content resolver default yang disediakan oleh sistem Android.

Dalam praktik ini, Anda akan membangun penyedia konten dasar dari awal. Anda akan membuat dan memproses data tiruan sehingga Anda bisa berfokus pada memahami arsitektur penyedia konten. Dengan demikian, antarmuka pengguna untuk menampilkan data adalah minimal. Dalam praktik selanjutnya, Anda akan menambahkan penyedia konten ke aplikasi WordList, menggunakan aplikasi minimalis ini sebagai template Anda.

Yang harus sudah Anda KETAHUI

Untuk praktik ini, Anda harus sudah memahami cara:

  • Membuat, membangun, dan menjalankan aplikasi interaktif di Android Studio.
  • Menampilkan data di sebuah RecyclerView menggunakan adaptor.
  • Mengabstraksi dan melingkupi data dengan model data.
  • Membuat, mengelola, dan berinteraksi dengan database SQLite menggunakan SQLiteOpenHelper.

Yang akan Anda PELAJARI

Anda akan mempelajari:

  • Arsitektur dan anatomi penyedia konten.
  • Apa yang perlu Anda lakukan untuk membangun penyedia konten minimal yang bisa Anda gunakan sebagai template untuk membuat penyedia konten lainnya.

Yang akan Anda LAKUKAN

  • Anda akan membangun aplikasi mandiri untuk mempelajari cara kerja pembangunan penyedia konten.

Ringkasan Aplikasi

  • Aplikasi ini menghasilkan data tiruan dan menyimpannya dalam daftar tertaut yang bernama "words".
  • Aplikasi meminta data melalui content resolver dan menampilkannya. UI terdiri dari satu aktivitas dengan TextView dan dua Tombol. Tombol "List all words" akan menampilkan semua kata dan tombol "List first word" menampilkan kata pertama di TextView.
  • Penyedia konten mengabstraksi dan mengelola interaksi antara sumber data dan antarmuka pengguna.
  • Contract mendefinisikan URI dan konstanta publik.

Layar aplikasi MinimalistContentProvider.

Catatan: Versi SDK minimum adalah API15: Android 4.0.3 IceCreamSandwich dan SDK target adalah versi Android saat ini (versi 23 saat buku ini ditulis).

Tugas 1. Membuat proyek MinimalistContentProvider

1.1. Buat proyek di dalam batasan yang diberikan

Buat aplikasi dengan satu aktivitas yang hanya menampilkan satu tampilan teks dan dua tombol. Satu tombol menampilkan kata pertama di data (daftar) dan tombol lainnya akan menampilkan semua kata. Kedua tombol memanggil onClickDisplayEntries() saat diklik. Untuk saat ini, metode ini akan menggunakan pernyataan switch hanya untuk menampilkan pernyataan bahwa tombol tertentu diklik. Gunakan tabel di bawah sebagai panduan untuk menyetel proyek Anda.

Nama aplikasi

MinimalistContentProvider

Satu Aktivitas

Template Empty Activity

Name: MainActivity

private static final String TAG = MainActivity.class.getSimpleName();

public void onClickDisplayEntries (View view){Log.d (TAG, "Yay, I was clicked!");}

TextView

@+id/textview

android:text="response"

Button

@+id/button_display_all

android:text="List all words"

android:onClick="onClickDisplayEntries"

Button

@+id/button_display_first

android:text="List first word"

android:onClick="onClickDisplayEntries"

1.2. Selesaikan persiapan dasar

Selesaikan persiapan dasar antarmuka pengguna:

  1. Di MainActivity, buat variabel anggota untuk tampilan teks dan lakukan inisialisasi di onCreate().
  2. Di onClickDisplayEntries(), gunakan pernyataan switch untuk memeriksa tombol mana yang ditekan. Gunakan view id untuk mengenali tombol. Cetak pernyataan log untuk setiap kasus.
  3. Di onClickDisplayEntries(), di bagian akhir, tambahkan beberapa teks ke TextView.
  4. Seperti biasanya, ekstrak sumber daya string.
  5. Jalankan aplikasi.

MainActivity seharusnya sama dengan solusi ini.

Solusi:

package android.example.com.minimalistcontentprovider;

[... imports]

public class MainActivity extends AppCompatActivity {

   private static final String TAG = MainActivity.class.getSimpleName();

   TextView mTextView;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
       mTextView = (TextView) findViewById(R.id.textview);
   }

   public void onClickDisplayEntries(View view) {
       Log.d (TAG, "Yay, I was clicked!");

       switch (view.getId()) {
           case R.id.button_display_all:
               Log.d (TAG, "Yay, " + R.id.button_display_all + " was clicked!");
               break;
           case R.id.button_display_first:
               Log.d (TAG, "Yay, " + R.id.button_display_first + " was clicked!");
               break;
           default:
               Log.d (TAG, "Error. This should never happen.");
       }
       mTextView.append("Thus we go! \n");
   }
}

Tugas 2: Membuat kelas Contract, URI, dan data tiruan

Contract berisi informasi tentang tentang data yang diperlukan aplikasi untuk membangun kueri.

  • Contract adalah kelas publik yang menyertakan informasi penting untuk aplikasi lain yang ingin terhubung dengan penyedia konten ini dan mengakses data Anda.
  • URI menampilkan cara membangun URI untuk mengakses data. Skema URI berperilaku sebagai API untuk mengakses data. Ini mirip dengan merancang panggilan REST untuk CRUD. Aplikasi lain akan menggunakan URI Konten ini.

2.1. Buat kelas Contract

  1. Buat kelas Java Contract publik yang baru dengan tanda tangan berikut. Ini harus final.
    public final class Contract {}
    
  2. Untuk mencegah seseorang tidak sengaja membuat instance kelas Contract, berikan constructor pribadi kosong.
    private Contract() {}
    

2.2 Buat URI

URI konten untuk penyedia konten memiliki bentuk umum berikut:

scheme://authority/path/id
  • scheme selalu content:// untuk URI konten.
  • authority (merepresentasikan domain, dan untuk penyedia konten biasanya berakhiran .provider)
  • path adalah jalur menuju data
  • id secara unik mengidentifikasi rangkaian data untuk ditelusuri

URI berikut bisa digunakan untuk meminta semua entri di tabel "words":

content://com.android.example.wordcontentprovider.provider/words

URI untuk mengakses penyedia konten didefinisikan di Contract sehingga hanya tersedia bagi aplikasi yang ingin melakukan kueri pada penyedia konten ini. Biasanya, ini dilakukan dengan mendefinisikan konstanta untuk AUTHORITY, CONTENT_PATH, dan CONTENT_URI

  1. Di kelas Contract, buat sebuah konstanta untuk AUTHORITY. Untuk menjadikan Authority unik, gunakan nama paket yang ditambah dengan "provider." public static final String AUTHORITY = "com.android.example.minimalistcontentprovider.provider";
  2. Buat konstanta untuk CONTENT_PATH. Jalur konten mengidentifikasi data. Anda harus menggunakan sesuatu yang deskriptif, misalnya, nama tabel atau file atau jenis data, misalnya "words".
    public static final String CONTENT_PATH = "words";
  3. Buat konstanta untuk CONTENT_URI. Ini adalah URI yang bergaya content:// yang menunjuk ke satu rangkaian data. Jika Anda memiliki beberapa "data container" di backend, Anda harus membuat URI konten untuk masing-masing data container tersebut.

    [URI[(https://developer.android.com/reference/android/net/Uri.html) adalah kelas helper untuk membangun dan memanipulasi URI. Karena ini tidak pernah berubah, string untuk semua instance kelas Contract, Anda bisa melakukan inisialisasi secara statis. public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + CONTENT_PATH);

  4. Buat konstanta bantu untuk ALL_ITEMS. Ini adalah nama kumpulan data yang akan Anda gunakan saat mengambil semua kata. Nilainya -2 karena ini adalah nilai terendah pertama yang tidak dikembalikan oleh panggilan metode. static final int ALL_ITEMS = -2;
  5. Buat konstanta bantu untuk WORD_ID. Ini adalah id yang akan Anda gunakan saat mengambil satu kata. static final String WORD_ID = "id";

2.3. Tambahkan Tipe MIME

Penyedia konten menyediakan konten dan Anda perlu menetapkan tipe konten seperti apa yang disediakannya. Aplikasi perlu mengetahui struktur dan format data yang dikembalikan, sehingga bisa menanganinya dengan benar.

Tip MIME adalah tipe/subtipe bentuk, seperti text/html untuk laman HTML. Untuk penyedia konten, Anda perlu mendefinisikan tipe MIME khusus vendor untuk jenis data yang dikembalikan oleh penyedia konten Anda. Tipe tipe MIME Android khusus vendor adalah selalu:

  • vnd.android.cursor.item untuk satu item data (sebuah catatan)
  • vnd.android.cursor.dir untuk kumpulan s data (beberapa catatan).

Subtipe bisa berupa apa pun, tetapi sebaiknya buat yang informatif. Misalnya:

  • vnd—tipe MIME vendor
  • com.example—domain
  • provider—untuk penyedia konten
  • words—nama tabel

Baca Mengimplementasikan Tipe MIME Penyedia Konten untuk detailnya.

  1. Deklarasikan tipe MIME untuk satu item data.
    static final String SINGLE_RECORD_MIME_TYPE = "vnd.android.cursor.item/vnd.com.example.provider.words";
    
  2. Deklarasikan tipe MIME untuk beberapa catatan.
    static final String MULTIPLE_RECORD_MIME_TYPE = "vnd.android.cursor.dir/vnd.com.example.provider.words";
    

2.4 Buat data tiruan

Penyedia konte selalu menyajikan hasil sebagai Cursor dalam format tabel yang mirip dengan database SQL. Ini terpisah dari bagaimana data sebenarnya disimpan. Aplikasi ini menggunakan larik string kata.

Dalam strings.xml, tambahkan satu daftar kata yang pendek:

<string-array name="words">
   <item>Android</item>
   <item>Activity</item>
   <item>ContentProvider</item>
   <item>ContentResolver</item>
</string-array>

Tugas 3: Mengimplementasikan kelas MiniContentProvider

3.1. Buat kelas MiniContentProvider

  1. Buat kelas Java MiniContentProvider yang memperluas ContentProvider. (Untuk praktik ini, jangan gunakan opsi menu Create Class > Other > Content Provider.)
  2. Implementasikan metode (Code > Implement methods).
  3. Tambahkan tag log.
  4. Tambahkan variabel anggota untuk data tiruan.
    public String[] mData;
    
  5. Di onCreate(), inisialisasikan mData dari larik kata dan kembalikan true.
    @Override
    public boolean onCreate() {
       Context context = getContext();
       mData = context.getResources().getStringArray(R.array.words);
       return true;
    }
    
  6. Tambahkan pesan log ke metode insert, delete, dan update. Anda tidak akan mengimplementasikan metode ini untuk praktik ini.
    Log.e(TAG, "Not implemented: update uri: " + uri.toString());
    

3.2. Terbtikan penyedia konten dengan menambahkannya ke manifest Android.

Untuk mengetahui penyedia konten, aplikasi Anda dan aplikasi lain perlu mengetahui bahwa penyedia konten ada. Tambahkan deklarasi untuk penyedia konten ke manifes Android di dalam sebuah .

Deklarasi berisi nama penyedia konten dan otoritas (identifier uniknya).

  1. Dalam AndroidManifest, di dalam tag aplikasi, setelah tag penutup aktivitas, tambahkan:
    <provider
        android:name=".MiniContentProvider"
    android:authorities="com.android.example.minimalistcontentprovider.provider" />
    
  2. Jalankan kode Anda untuk memastikan dikompilasi dengan baik.

3.3. Persiapkan pencocokan URI

ContentProvider perlu merespons permintaan data dari aplikasi menggunakan sejumlah URI yang berbeda. Untuk mengambil tindakan yang sesuai bergantung pada URI permintaan tertentu, penyedia konten harus menganalisis URI untuk melihat apakah cocok. UriMatcher adalah kelas helper yang bisa Anda gunakan untuk memproses skema URI yang diterima untuk penyedia konten yang diberikan.

Langkah-langkah dasar untuk menggunakan UriMatcher:

  • Buat instance UriMatcher
  • Tambahkan setiap URI yang dikenali penyedia konten Anda ke UriMatcher.
  • Tetapkan konstanta numerik ke setiap URI. Memiliki konstanta numeri untuk setiap URI memudahkan Anda saat Anda memproses URI yang masuk karena Anda bisa menggunakan pernyataan switch/case pada nilai numerik untuk memproses URI.

Buat perubahan berikut di kelas MiniContentProvider.

  1. Dalam kelas MiniContentProvider, buat variabel statis pribadi untuk UriMatcher.

    Argumen untuk constructor menentukan nilai untuk dikembalikan jika tidak ada kecocokan. Sebagai praktik terbaik, gunakan UriMatcher.NO_MATCH.

    private static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    
  2. Buat metode Anda sendiri untuk menginisialisasi URI matcher.
    private void initializeUriMatching(){}
    
  3. Panggil initializeUriMatching di onCreate() kelas MiniContentProvider.
  4. Dalam metode initializeUriMatching(), tambahkan URI yang diterima penyedia konten Anda ke matcher dan tetapkan sebagai kode integer. Ini adalah URI berdasarkan otoritas dan jalur konten yang ditetapkan di Contract.

    Simbol # mencocokkan string karakter numerik dengan panjang berapa saja. Di aplikasi ini, ini mengacu pada indeks kata di larik string. Di aplikasi produksi, ini bisa jadi id entri dalam database. Tetapkan URI ini nilai numerik 1.

    sUriMatcher.addURI(Contract.AUTHORITY, Contract.CONTENT_PATH + "/#", 1);
    
  5. URI kedua adalah yang Anda tentukan di Contract untuk mengembalikan semua item. Tetapkan nilai numerik 0. sUriMatcher.addURI(Contract.AUTHORITY, Contract.CONTENT_PATH, 0);

Perhatikan bahwa aplikasi Anda lebih kompleks dan menggunakan lebih banyak URI, menggunakan konstanta bernama untuk kode, seperti yang ditampilkan di dokumentasi UriMatcher.

Solusi:

private void initializeUriMatching(){
   sUriMatcher.addURI(Contract.AUTHORITY, Contract.CONTENT_PATH + "/#", 1);
   sUriMatcher.addURI(Contract.AUTHORITY, Contract.CONTENT_PATH, 0);
}

3.4 Implementasikan metode getType()

Metode getType() penyedia konten mengembalikan tipe MIME untuk setiap URI yang ditetapkan.

Kecuali Anda melakukan sesuatu yang khusus di kode Anda, implementasi metode ini akan sangat mirip untuk penyedia konten apa pun. Ini melakukan yang berikut:

  1. Mencocokkan URI.
  2. Mengaktifkan kode yang dikembalikan.
  3. Mengembalikan tipe MIME yang sesuai.

Pelajari selengkapnya di dokumentasi UriMatcher.

Solusi:

public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)) {
            case 0:
                return Contract.MULTIPLE_RECORD_MIME_TYPE;
            case 1:
                return Contract.SINGLE_RECORD_MIME_TYPE;
            default:
                // Alternatively, throw an exception.
                return null;
        }
    }

3.5 Implementasikan metode query()

Tujuan metode query() adalah untuk mencocokkan URI, mengonversinya ke mekanisme akses data internal Anda (misalnya, kueri SQLite), mengeksekusi kode akses data internal, dan mengembalikan hasil di objek Cursor.

Metode query()

Metode query memiliki tanda tangan berikut:

public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder){}

Argumen ke metode ini merepresentasikan bagian kueri SQL. Bahkan jika Anda menggunakan jenis mekanisme storage data lain, Anda masih harus menerima kueri dengan gaya ini dan menangani argumen dengan benar. (Di tugas berikutnya, Anda akan membangun kueri di MainActivity untuk melihat bagaimana argumen digunakan.) Metode mengembalikan Cursor dengan jenis apa pun.

uri

URI lengkap. Ini tidak boleh null.

projection

Menunjukkan kolom/atribut mana untuk diakses.

selection

Menunjukkan baris/catatan objek mana untuk diakses.

selectionArgs

Parameter yang melekat pada argumen pilihan sebelumnya.

Untuk alasan keamanan, argumen diproses terpisah.

sortOrder

Apakah akan mengurutkan, dan jika demikian, apakah naik, turun, atau berdasarkan.

Jika ini null, pengurutan default atau tanpa pengurutan akan diterapkan.

Analisis metode query()

  1. Identifikasi langkah-langkah pemrosesan berikut di kode metode kueri() yang ditampilkan di bawah di bagian solusi.

    Pemrosesan kueri selalu terdiri dari langkah-langkah ini:

    1. Mencocokkan URI.

    2. Mengaktifkan kode yang dikembalikan.

    3. Memproses argumen dan membangun kueri yang sesuai untuk backed.

    4. Dapatkan data dan (jika perlu) masukkan ke dalam Cursor.

    5. Kembalikan kursor.

  2. Identifikasi bagian kode yang perlu diubah di aplikasi dunia nyata.

    Implementasi kueri untuk aplikasi dasar ini mengambil beberapa pintasan.

    • Penanganan kesalahan minimal.
    • Karena aplikasi menggunakan data tiruan, Cursor bisa diisi secara langsung.
    • Karena skema URI sederhana, metode ini cukup singkat.
  3. Identifikasi setidaknya satu keputusan desain yang memudahkan pemahaman dan pengelolaan kode.
    • Menganalisis kueri dan mengeksekusinya untuk mengisi kursor dipisahkan ke dalam dua metode.
    • Kode berisi lebih banyak kode daripada kode yang bisa dieksekusi.
  4. Tambahkan kode ke aplikasi Anda.

Catatan: Anda akan mendapatkan kesalahan untuk metode populateCursor() dan akan menanganinya langkah berikutnya.

Kode Solusi dengan Anotasi untuk metode query() di MiniContentProvider.java

@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
   int id = -1;
   switch (sUriMatcher.match(uri)) {
       case 0:
           // Matches URI to get all of the entries.
           id = Contract.ALL_ITEMS;
           // Look at the remaining arguments
           // to see whether there are constraints.
           // In this example, we only support getting
           //a specific entry by id. Not full search.
           // For a real-life app, you need error-catching code;
           // here we assume that the
           // value we need is actually in selectionArgs and valid.
           if (selection != null){
               id = parseInt(selectionArgs[0]);
           }
           break;

       case 1:
           // The URI ends in a numeric value, which represents an id.
           // Parse the URI to extract the value of the last,
           // numeric part of the path,
           // and set the id to that value.
           id = parseInt(uri.getLastPathSegment());
           // With a database, you would then use this value and
           // the path to build a query.
           break;

       case UriMatcher.NO_MATCH:
           // You should do some error handling here.
           Log.d(TAG, "NO MATCH FOR THIS URI IN SCHEME.");
           id = -1;
           break;
       default:
           // You should do some error handling here.
           Log.d(TAG, "INVALID URI - URI NOT RECOGNIZED.");
           id = -1;
   }
   Log.d(TAG, "query: " + id);
   return populateCursor(id);
}

3.6. Implementasikan metode populateCursor()

Setelah metode query() telah mengidentifikasi URI, metode akan memanggil populateCursor() Anda dengan segmen jalur terakhir, yang merupakan id (indeks) kata yang akan diambil. Metode populateCursor() memisahkan pencocokan kueri dari mendapatkan data dan membuat kursor hasil. Ini adalah praktik terbaik seperti di aplikasi nyata, metode query() bisa menjadi sangat besar.

Metode query harus mengembalikan tipe Cursor, sehingga metode populateCursor() harus membuat, mengisi, dan mengembalikan kursor.

  • Jika data Anda disimpan di database SQLite, mengeksekusi kueri akan mengembalikan sebuah Cursor.
  • Jika Anda tidak menggunakan metode storage data yang mengembalikan kursor, seperti file atau data tiruan, Anda bisa menggunakan MatrixCursor untuk menampung data yang akan dikembalikan. MatrixCursor adalah kursor untuk penggunaan umum ke dalam larik objek yang terus bertambah sesuai kebutuhan. Untuk membuat MatrixCursor, Anda harus mengisinya dengan larik string nama kolom.

Metode populateCursor() melakukan yang berikut:

  1. Menerima id yang diekstrak dari URI.
  2. Membuat MatrixCursor untuk menyimpan data yang diterima (karena data tiruan yang diterima bukan kursor).
  3. Membuat dan mengeksekusi kueri. Untuk aplikasi ini, ini akan mengambil string di indeks id dari larik string. Dalam aplikasi yang lebih realistis, ini bisa mengeksekusi kueri ke database.
  4. Menambahkan hasil ke kursor.
  5. Mengembalikan kursor.
    private Cursor populateCursor(int id) {
       MatrixCursor cursor = new MatrixCursor(new String[] { Contract.CONTENT_PATH });
       // If there is a valid query, execute it and add the result to the cursor.
       if (id == Contract.ALL_ITEMS) {
           for (int i = 0; i < mData.length; i++) {
               String word = mData[i];
               cursor.addRow(new Object[]{word});
           }
       } else if (id >= 0) {
           // Execute the query to get the requested word.
           String word = mData[id];
           // Add the result to the cursor.
           cursor.addRow(new Object[]{word});
       }
       return cursor;
    }
    

Tugas 4: Menggunakan ContentResolver untuk mendapatkan data

Setelah mempersiapkan penyedia konten, metode onClickDisplayEntries() di MainActivity bisa diluaskan untuk melakukan kueri dan menampilkan data ke UI. Ini memerlukan langkah-langkah berikut:

  1. Buat kueri bergaya SQL, bergantung pada tombol mana yang ditekan.
  2. Gunakan content resolver untuk berinteraksi dengan penyedia konten untuk mengeksekusi kueri dan mengembalikan sebuah Cursor.
  3. Proses hasilnya di Cursor.

4.1. Dapatkan content resolver

Content resolver berinteraksi dengan penyedia konten atas nama Anda.

Content resolver mengharapkan URI Content yang di-parse bersama dengan parameter kueri yang membantu mengambil data.

Anda tidak harus membuat content resolver sendiri. Anda bisa menggunakan yang disediakan di konteks aplikasi Anda oleh framework Android dengan memanggil getContentResolver().

  1. Di MainActivity, hapus semua kode dari dalam onClickDisplayEntries().
  2. Tambahkan kode ini ke onClickDisplayEntries() di MainActivity.
    Cursor cursor = getContentResolver().query(Uri.parse(queryUri), projection, selectionClause, selectionArgs, sortOrder);
    
    Perhatikan: argumen ke getContentResolver.query() sama dengan parameter ContentProvider.query().

Selanjutnya, Anda harus mendefinisikan argumen ke getContentResolver.query().

4.2. Definisikan argumen kueri

Agar getContentResolver.query() bisa berfungsi, Anda harus mendeklarasikan dan menetapkan nilai ke semua argumennya.

  1. URI: Deklarasikan ContentURI yang mengidentifikasi penyedia konten dan tabel. Dapatkan informasi untuk URI yang benar dari contract.
    String queryUri = Contract.CONTENT_URI.toString();
    
  2. Projection: Sebuah larik string dengan nama kolom untuk dikembalikan. Menyetel ini ke null akan mengembalikan semua kolom. Jika hanya ada satu kolom, seperti di contoh ini, menyetel ini secara eksplisit adalah opsional, tetapi bisa berguna untuk tujuan dokumentasi. // Only get words. String[] projection = new String[] {Contract.CONTENT_PATH};
  3. selectionClause: Klausa argumen untuk kriteria pilihan, yaitu, baris mana yang akan dikembalikan. Diformat sebagai klausa SQL WHERE (mengecualikan kata kunci "WHERE"). Meneruskan null akan mengembalikan semua baris untuk tampilan URI yang diberikan. Karena ini akan berbeda sesuai dengan tombol mana yang ditekan, deklarasikan ini sekarang dan setel nanti.
    String selectionClause;
    
  4. selectionArgs: Nilai argumen untuk kriteria pilihan. Jika Anda menyertakan ? di String selection, ? akan digantikan oleh nilai dari selectionArgs, dengan urutan munculnya.
    PENTING: Praktik terbaik keamanan adalah selalu memisahkan selection dan selectionArgs.
    String selectionArgs[];
  5. sortOrder: Urutan untuk mengurutkan hasil. Diformat sebagai klausa SQL ORDER BY (mengecualikan kata kunci ORDER BY). Biasanya ASC atau DESC; null meminta tata urutan default, yang bisa jadi tidak berurutan.
    // For this example, accept the order returned by the response.
    String sortOrder = null;
    

4.3. Putuskan kriteria selection

Nilai selectionClause dan selectionArgs bergantung pada tombol mana yang ditekan di UI.

  • Untuk menampilkan semua kata, setel kedua argumen ke null.
  • Untuk mendapatkan kata pertama, kueri kata dengan ID 0. (Ini mengasumsikan bahwa ID kata dimulai dari 0 dan dibuat sesuai urutan. Anda mengetahui ini, karena informasinya diperlihatkan di contract. Untuk penyedia konten yang berbeda, sebaiknya ketahui id-nya dan telusuri dengan cara yang berbeda.)
  1. Ganti blok switch yang sudah ada dengan kode berikut ini di onClickDisplayEntries, sebelum Anda mendapatkan content resolver.
    switch (view.getId()) {
       case R.id.button_display_all:
           selectionClause = null;
           selectionArgs = null;
           break;
       case R.id.button_display_first:
           selectionClause = Contract.WORD_ID + " = ?";
           selectionArgs = new String[] {"0"};
           break;
       default:
           selectionClause = null;
           selectionArgs = null;
    }
    

4.4. Proses Cursor

Setelah mendapatkan content resolver, Anda harus memproses hasil dari Cursor.

  • Jika ada data, tampilkan di TextView.
  • Jika tidak ada data, laporkan kesalahan.
  1. Periksa kode berikut dan pastikan Anda memahami semuanya.
       if (cursor != null) {
       if (cursor.getCount() > 0) {
           cursor.moveToFirst();
           int columnIndex = cursor.getColumnIndex(projection[0]);
           do {
               String word = cursor.getString(columnIndex);
               mTextView.append(word + "\n");
           } while (cursor.moveToNext());
       } else {
           Log.d(TAG, "onClickDisplayEntries " + "No data returned.");
           mTextView.append("No data returned." + "\n");
       }
       cursor.close();
    } else {
       Log.d(TAG, "onClickDisplayEntries " + "Cursor is null.");
       mTextView.append("Cursor is null." + "\n");
    }
    
  2. Sisipkan kode ini di akhir onClickDisplayEntry().
  3. Jalankan aplikasi Anda.
  4. Klik tombol untuk melihat data yang diambil di TextView.

Kode solusi

Proyek Android Studio: MinimalistContentProvider

Tantangan penyusunan kode

Catatan: Semua tantangan penyusunan kode opsional dan bukan prasyarat untuk pelajaran berikutnya.

Mengimplementasikan metode yang tidak ada

Tantangan Penyusunan Kode 1: Implementasikan metode insert, delete, dan update untuk aplikasi MinimalistContentProvider. Berikan cara kepada pengguna untuk menyisipkan, menghapus, dan memperbarui data.

Petunjuk: Jika Anda tidak ingin membangun antarmuka pengguna, buat tombol untuk setiap tindakan dan mengaitkan data yang disisipkan, diperbarui, dan dihapus. Latihan ini ditujukan untuk bekerja dengan penyedia konten, bukan antarmuka pengguna.

Mengapa: Anda akan mengimplementasikan penyedia konten yang sepenuhnya berfungsi dengan UI di praktik berikutnya, ketika Anda menambahkan penyedia konten ke aplikasi WordListSQL.

Menambahkan Pengujian Unit untuk penyedia konten

Tantangan Penyusunan Kode 2: Setelah Anda mengimplementasikan penyedia konten, Anda tidak memiliki cara untuk mengetahui apakah kode bekerja atau tidak. Dalam contoh ini, Anda membangun front-end dan dengan memperhatikan cara kerjanya, Anda mengasumsikan aplikasi bekerja dengan benar. Dalam aplikasi dunia nyata, ini saja tidak cukup dan Anda mungkin tidak memiliki akses ke front-end. Cara yang sesuai untuk menentukan apakah setiap metode berfungsi sesuai harapan, tuliskan pengujian unit untuk MiniContentProvider.

Rangkuman

Pada bab ini, Anda telah mempelajari

  • Penyedia konten adalah abstraksi data tingkat tinggi yang mengelola akses ke repositori bersama
  • Penyedia konten utamanya ditujukan untuk digunakan oleh aplikasi selain aplikasi Anda sendiri.
  • Penyedia konten (sisi-server) diakses oleh Content Resolver (sisi-aplikasi)
  • Contract adalah kelas publik yang mengekspos informasi penting tentang penyedia konten.
  • Contract bisa berguna di luar penyedia konten.
  • Penyedia konten perlu mendefinisikan serangkaian URI konten sehingga aplikasi bisa mengakses data melalui penyedia konten Anda.
  • URI konten terdiri dari beberapa komponen: "content://", sebuah otoritas konten yang unik (biasanya berupa nama paket yang sepenuhnya berkualifikasi) dan content-path.
  • Gunakan content resolver untuk meminta data dari penyedia konten dan menampilkannya kepada pengguna.
  • Jika aplikasi Anda tidak berbagi data dengan aplikasi lain, aplikasi Anda tidak memerlukan penyedia konten.
  • Penyedia konten harus mengimplementasikan metode getType() yang mengembalikan tipe MIME untuk setiap tipe konten.
  • Penyedia konten perlu "diterbitkan" di manifes Android menggunakan elemendi dalam elemen .
  • Penyedia konten perlu memeriksa URI masuk untuk menentukan kecocokan pola URI untuk mengakses data apa pun.
  • Anda harus menambahkan pola URI target ke penyedia konten Anda. Kelas UriMatcher adalah kelas yang berguna untuk tujuan ini.
  • Inti penyedia konten diimplementasikan di metode query()-nya.
  • Tanda tangan metode dari metode query() dalam content resolver (peminta data) cocok dengan tanda tangan metode dari metode query() dalam penyedia konten (sumber data).
  • Metode query() mengembalikan objek cursor bergaya database dengan tidak mempertimbangkan apakah data bersifat relasional atau tidak.

[Konsep terkait]

Dokumentasi konsep terkait ada di Dasar-Dasar Developer Android: Konsep.

Ketahui selengkapnya

Dokumentasi Developer

results matching ""

    No results matching ""