AppSearch adalah solusi penelusuran di perangkat berperforma tinggi untuk mengelola data terstruktur yang disimpan secara lokal. AppSearch berisi API untuk mengindeks data dan mengambil data menggunakan penelusuran teks lengkap. Aplikasi dapat menggunakan AppSearch untuk menawarkan kemampuan penelusuran dalam aplikasi kustom, sehingga pengguna dapat menelusuri konten bahkan saat offline.
AppSearch menyediakan fitur berikut:
- Implementasi penyimpanan yang cepat dan mengutamakan perangkat seluler dengan penggunaan I/O yang rendah
- Pengindeksan dan pembuatan kueri yang sangat efisien pada set data besar
- Dukungan multibahasa, seperti bahasa Inggris dan Spanyol
- Peringkat relevansi dan penilaian penggunaan
Karena penggunaan I/O yang lebih rendah, AppSearch menawarkan latensi yang lebih rendah untuk pengindeksan dan penelusuran pada set data besar dibandingkan dengan SQLite. AppSearch menyederhanakan kueri lintas jenis dengan mendukung kueri tunggal, sedangkan SQLite menggabungkan hasil dari beberapa tabel.
Untuk mengilustrasikan fitur AppSearch, mari kita ambil contoh aplikasi musik yang mengelola lagu favorit pengguna dan memungkinkan pengguna menelusurinya dengan mudah. Pengguna menikmati musik dari seluruh dunia dengan judul lagu dalam berbagai bahasa, yang pengindeksan dan kuerinya didukung secara native oleh AppSearch. Saat pengguna menelusuri lagu berdasarkan judul atau nama artis, aplikasi cukup meneruskan permintaan ke AppSearch untuk mengambil lagu yang cocok dengan cepat dan efisien. Aplikasi akan menampilkan hasilnya, sehingga pengguna dapat dengan cepat mulai memutar lagu favorit mereka.
Penyiapan
Untuk menggunakan AppSearch di aplikasi Anda, tambahkan dependensi berikut ke file build.gradle aplikasi Anda:
Groovy
dependencies { def appsearch_version = "1.2.0-alpha02" implementation "androidx.appsearch:appsearch:$appsearch_version" // Use kapt instead of annotationProcessor if writing Kotlin classes annotationProcessor "androidx.appsearch:appsearch-compiler:$appsearch_version" implementation "androidx.appsearch:appsearch-local-storage:$appsearch_version" // PlatformStorage is compatible with Android 12+ devices and supports sharing data // with other apps. Feature support varies by device. Before calling an API that // requires a feature, check Features.isFeatureSupported(). implementation "androidx.appsearch:appsearch-platform-storage:$appsearch_version" // PlayServicesStorage is compatible with all devices that support Google Play Services on // all API levels. It offers similar capabilities to PlatformStorage and is the // recommended solution for lower API levels on which PlatformStorage is not supported. implementation "androidx.appsearch:appsearch-play-services-storage:$appsearch_version" }
Kotlin
dependencies { val appsearch_version = "1.2.0-alpha02" implementation("androidx.appsearch:appsearch:$appsearch_version") // Use annotationProcessor instead of kapt if writing Java classes kapt("androidx.appsearch:appsearch-compiler:$appsearch_version") implementation("androidx.appsearch:appsearch-local-storage:$appsearch_version") // PlatformStorage is compatible with Android 12+ devices and supports sharing data // with other apps. Feature support varies by device. Before calling an API that // requires a feature, check Features.isFeatureSupported(). implementation("androidx.appsearch:appsearch-platform-storage:$appsearch_version") // PlayServicesStorage is compatible with all devices that support Google Play Services on // all API levels. It offers similar capabilities to PlatformStorage and is the // recommended solution for lower API levels on which PlatformStorage is not supported. implementation("androidx.appsearch:appsearch-play-services-storage:$appsearch_version") }
Konsep AppSearch
Diagram berikut mengilustrasikan konsep AppSearch dan interaksinya.
Gambar 1. Diagram konsep AppSearch: database AppSearch, skema,
jenis skema, dokumen, sesi, dan penelusuran.
Database dan sesi
Database AppSearch adalah kumpulan dokumen yang sesuai dengan skema database. Aplikasi klien membuat database dengan memberikan konteks aplikasi dan nama database. Database hanya dapat dibuka oleh aplikasi yang membuatnya. Saat database dibuka, sesi akan ditampilkan untuk berinteraksi dengan database. Sesi adalah titik entri untuk memanggil AppSearch API dan tetap terbuka hingga ditutup oleh aplikasi klien.
Skema dan jenis skema
Skema mewakili struktur organisasi data dalam database AppSearch.
Skema terdiri dari jenis skema yang mewakili jenis data unik. Jenis skema terdiri dari properti yang berisi nama, jenis data, dan kardinalitas. Setelah jenis skema ditambahkan ke skema database, dokumen dari jenis skema tersebut dapat dibuat dan ditambahkan ke database.
Dokumen
Di AppSearch, unit data direpresentasikan sebagai dokumen. Setiap dokumen dalam database AppSearch diidentifikasi secara unik berdasarkan namespace dan ID-nya. Namespace digunakan untuk memisahkan data dari berbagai sumber saat hanya satu sumber yang perlu dikueri, seperti akun pengguna.
Dokumen berisi stempel waktu pembuatan, time-to-live (TTL), dan skor yang dapat digunakan untuk memberi peringkat selama pengambilan. Dokumen juga diberi jenis skema yang menjelaskan properti data tambahan yang harus dimiliki dokumen.
Class dokumen adalah abstraksi dokumen. Entitas ini berisi kolom yang dianotasi yang mewakili konten dokumen. Secara default, nama class dokumen menetapkan nama jenis skema.
Telusuri
Dokumen diindeks dan dapat ditelusuri dengan memberikan kueri. Dokumen akan dicocokkan dan disertakan dalam hasil penelusuran jika berisi istilah dalam kueri atau cocok dengan spesifikasi penelusuran lainnya. Hasil diurutkan berdasarkan skor dan strategi peringkatnya. Hasil penelusuran diwakili oleh halaman yang dapat Anda ambil secara berurutan.
AppSearch menawarkan penyesuaian untuk penelusuran, seperti filter, konfigurasi ukuran halaman, dan cuplikan.
Penyimpanan Platform, Penyimpanan Lokal, atau Penyimpanan Layanan Play
AppSearch menawarkan tiga solusi penyimpanan: LocalStorage, PlatformStorage, dan
PlayServicesStorage. Dengan LocalStorage, aplikasi Anda mengelola
indeks khusus aplikasi yang berada di direktori data aplikasi Anda. Dengan
PlatformStorage dan PlayServicesStorage, aplikasi Anda berkontribusi pada
indeks pusat di seluruh sistem. Indeks PlatformStorage dihosting di server
sistem dan indeks PlayServicesStorage dihosting di penyimpanan
Layanan Google Play. Akses data dalam indeks pusat ini dibatasi untuk data yang telah dikontribusikan oleh aplikasi Anda dan data yang telah dibagikan secara eksplisit kepada Anda oleh aplikasi lain. Semua opsi penyimpanan ini menggunakan API yang sama dan dapat
dipertukarkan berdasarkan versi perangkat.
Perlu diingat bahwa dukungan fitur bervariasi menurut opsi penyimpanan dan perangkat. Untuk mengetahui informasi selengkapnya, lihat Memeriksa ketersediaan fitur.
Kode berikut membuat sesi PlatformStorage di Android 12
(level API 31) dan yang lebih tinggi, serta sesi PlayServicesStorage atau LocalStorage
di versi yang lebih lama:
Kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { appSearchSessionFuture.setFuture( PlatformStorage.createSearchSession( PlatformStorage.SearchContext.Builder(mContext, DATABASE_NAME) .build() ) ) } else { if (usePlayServicesStorageBelowS) { appSearchSessionFuture.setFuture( PlayServicesStorage.createSearchSession( PlayServicesStorage.SearchContext.Builder(mContext, DATABASE_NAME) .build() ) ) } else { appSearchSessionFuture.setFuture( LocalStorage.createSearchSession( LocalStorage.SearchContext.Builder(mContext, DATABASE_NAME) .build() ) ) } }
Java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { mAppSearchSessionFuture.setFuture(PlatformStorage.createSearchSession( new PlatformStorage.SearchContext.Builder(mContext, DATABASE_NAME) .build())); } else { if (usePlayServicesStorageBelowS) { mAppSearchSessionFuture.setFuture(PlayServicesStorage.createSearchSession( new PlayServicesStorage.SearchContext.Builder(mContext, DATABASE_NAME) .build())); } else { mAppSearchSessionFuture.setFuture(LocalStorage.createSearchSession( new LocalStorage.SearchContext.Builder(mContext, DATABASE_NAME) .build())); } }
Dengan menggunakan PlatformStorage dan PlayServicesStorage, aplikasi Anda dapat
berbagi data secara aman dengan aplikasi lain agar aplikasi tersebut juga dapat menelusuri
data aplikasi Anda. Berbagi data aplikasi hanya baca diberikan
menggunakan handshake sertifikat untuk memastikan bahwa aplikasi lain memiliki
izin untuk membaca data. Baca selengkapnya tentang API ini dalam dokumentasi untuk setSchemaTypeVisibilityForPackage().
Selain itu, dengan PlatformStorage, data yang diindeks dapat ditampilkan
di platform UI Sistem. Aplikasi dapat memilih untuk tidak menampilkan sebagian atau semua datanya
di platform UI Sistem. Baca selengkapnya tentang API ini dalam dokumentasi untuk setSchemaTypeDisplayedBySystem().
| Fitur | LocalStorage (kompatibel dengan Android 5.0+) |
PlatformStorage (kompatibel dengan Android 12 atau yang lebih baru) |
PlayServicesStorage (kompatibel dengan Android 5.0+) |
|---|---|---|---|
| Penelusuran teks lengkap yang efisien | |||
| Dukungan multibahasa | |||
| Ukuran biner yang lebih kecil | |||
| Berbagi data antar-aplikasi | |||
| Kemampuan untuk menampilkan data di platform UI Sistem | |||
| Ukuran dan jumlah dokumen yang dapat diindeks tidak terbatas | |||
| Operasi yang lebih cepat tanpa latensi binder tambahan |
Ada konsekuensi tambahan yang perlu dipertimbangkan saat memilih antara LocalStorage
dan PlatformStorage. Karena PlatformStorage menggabungkan API Jetpack melalui
layanan sistem AppSearch, dampak ukuran APK minimal dibandingkan dengan menggunakan
LocalStorage. Namun, hal ini juga berarti operasi AppSearch menimbulkan latensi binder tambahan saat memanggil layanan sistem AppSearch. Dengan PlatformStorage
, AppSearch membatasi jumlah dokumen dan ukuran dokumen yang dapat diindeks
oleh aplikasi untuk memastikan indeks pusat yang efisien. PlayServicesStorage juga memiliki
batasan yang sama dengan PlatformStorage dan hanya didukung di perangkat dengan
layanan Google Play.
Periksa ketersediaan fitur
Meskipun semua opsi penyimpanan menggunakan API yang sama, beberapa fitur tidak tersedia
dengan setiap opsi penyimpanan atau di setiap perangkat. Dalam referensi API, anotasi @RequiresFeature mengidentifikasi API yang memerlukan salah satu fitur
ini, dan class Features
menentukan konstanta untuk setiap fitur. Misalnya,
INDEXING_TYPE_RANGE
memerlukan Features.NUMERIC_SEARCH.
Untuk PlatformStorage, dukungan fitur bergantung pada versi Android perangkat.
Mulai Android 13 (API level 33), dukungan fitur juga bergantung pada
update sistem Google Play yang telah diterima perangkat. Misalnya,
PlatformStorage mendukung penelusuran numerik (Features.NUMERIC_SEARCH), penelusuran
verbatim (Features.VERBATIM_SEARCH), dan penggabungan
(Features.JOIN_SPEC_AND_QUALIFIED_ID) hanya di perangkat berikut:
- Perangkat yang menjalankan Android 14 (level API 34) atau yang lebih tinggi.
- Perangkat yang menjalankan Android 13 (level API 33) dan telah menerima update sistem Google Play yang diperlukan.
Fitur ini tidak didukung di perangkat yang menjalankan Android 12 atau Android 12L (API level 31 dan 32).
Jumlah maksimum properti yang diindeks dalam dokumen juga bervariasi menurut perangkat
dan opsi penyimpanan. Untuk mendapatkan batas saat runtime, panggil
getMaxIndexedProperties().
Jangan hanya mengandalkan versi Android untuk menentukan dukungan fitur. Sebelum
memanggil API yang memerlukan fitur, pastikan fitur tersebut didukung
dengan memanggil
isFeatureSupported()
pada objek Features yang
ditampilkan
AppSearchSession.getFeatures(). Jika fitur yang diperlukan tidak didukung, operasi akan gagal dengan pengecualian. Contoh kasus kegagalan adalah menetapkan skema yang menyertakan
properti INDEXING_TYPE_RANGE gagal di perangkat yang tidak mendukung
Features.NUMERIC_SEARCH.
Kode berikut memeriksa apakah AppSearchSession yang terbuka mendukung penelusuran numerik:
Kotlin
val features = session.features if (features.isFeatureSupported(Features.NUMERIC_SEARCH)) { // Numeric search is supported. You can index properties with // LongPropertyConfig.INDEXING_TYPE_RANGE and enable numeric search with // SearchSpec.Builder.setNumericSearchEnabled(true). } else { // Numeric search isn't supported. Set a schema without range-indexed // properties, or switch to a different storage option. }
Java
Features features = session.getFeatures(); if (features.isFeatureSupported(Features.NUMERIC_SEARCH)) { // Numeric search is supported. You can index properties with // LongPropertyConfig.INDEXING_TYPE_RANGE and enable numeric search with // SearchSpec.Builder.setNumericSearchEnabled(true). } else { // Numeric search isn't supported. Set a schema without range-indexed // properties, or switch to a different storage option. }
Mulai menggunakan AppSearch
Contoh di bagian ini menunjukkan cara menggunakan AppSearch API untuk berintegrasi dengan aplikasi pencatatan hipotetis.
Menulis class dokumen
Langkah pertama untuk berintegrasi dengan AppSearch adalah menulis class dokumen untuk
mendeskripsikan data yang akan dimasukkan ke dalam database. Tandai class sebagai class dokumen
menggunakan anotasi @Document.Anda dapat menggunakan instance class dokumen untuk memasukkan dokumen ke dalam dan
mengambil dokumen dari database.
Kode berikut menentukan class dokumen Note dengan kolom yang dianotasi
@Document.StringProperty
untuk mengindeks teks objek Note.
Kotlin
@Document public data class Note( // Required field for a document class. All documents MUST have a namespace. @Document.Namespace val namespace: String, // Required field for a document class. All documents MUST have an Id. @Document.Id val id: String, // Optional field for a document class, used to set the score of the // document. If this is not included in a document class, the score is set // to a default of 0. @Document.Score val score: Int, // Optional field for a document class, used to index a note's text for this // document class. @Document.StringProperty(indexingType = AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES) val text: String )
Java
@Document public class Note { // Required field for a document class. All documents MUST have a namespace. @Document.Namespace private final String namespace; // Required field for a document class. All documents MUST have an Id. @Document.Id private final String id; // Optional field for a document class, used to set the score of the // document. If this is not included in a document class, the score is set // to a default of 0. @Document.Score private final int score; // Optional field for a document class, used to index a note's text for this // document class. @Document.StringProperty(indexingType = StringPropertyConfig.INDEXING_TYPE_PREFIXES) private final String text; Note(@NonNull String id, @NonNull String namespace, int score, @NonNull String text) { this.id = Objects.requireNonNull(id); this.namespace = Objects.requireNonNull(namespace); this.score = score; this.text = Objects.requireNonNull(text); } @NonNull public String getNamespace() { return namespace; } @NonNull public String getId() { return id; } public int getScore() { return score; } @NonNull public String getText() { return text; } }
Membuka database
Anda harus membuat database sebelum menggunakan dokumen. Kode berikut
membuat database baru dengan nama notes_app dan mendapatkan ListenableFuture
untuk AppSearchSession,
yang mewakili koneksi ke database dan menyediakan API untuk
operasi database.
Kotlin
val context: Context = getApplicationContext() val sessionFuture = LocalStorage.createSearchSession( LocalStorage.SearchContext.Builder(context, /*databaseName=*/"notes_app") .build() )
Java
Context context = getApplicationContext(); ListenableFuture<AppSearchSession> sessionFuture = LocalStorage.createSearchSession( new LocalStorage.SearchContext.Builder(context, /*databaseName=*/ "notes_app") .build() );
Menetapkan skema
Anda harus menetapkan skema sebelum dapat memasukkan dokumen ke dalam dan mengambil dokumen dari database. Skema database terdiri dari berbagai jenis data terstruktur, yang disebut sebagai "jenis skema". Kode berikut menetapkan skema dengan menyediakan class dokumen sebagai jenis skema.
Kotlin
val setSchemaRequest = SetSchemaRequest.Builder().addDocumentClasses(Note::class.java) .build() val setSchemaFuture = Futures.transformAsync( sessionFuture, { session -> session?.setSchema(setSchemaRequest) }, mExecutor )
Java
SetSchemaRequest setSchemaRequest = new SetSchemaRequest.Builder().addDocumentClasses(Note.class) .build(); ListenableFuture<SetSchemaResponse> setSchemaFuture = Futures.transformAsync(sessionFuture, session -> session.setSchema(setSchemaRequest), mExecutor);
Menempatkan dokumen di database
Setelah jenis skema ditambahkan, Anda dapat menambahkan dokumen dari jenis tersebut ke database.
Kode berikut membuat dokumen jenis skema Note menggunakan builder class dokumen Note. Namespace dokumen user1 ditetapkan untuk mewakili pengguna arbitrer dari contoh ini. Dokumen kemudian dimasukkan ke dalam database
dan pemroses dipasang untuk memproses hasil operasi put.
Kotlin
val note = Note( namespace="user1", id="noteId", score=10, text="Buy fresh fruit" ) val putRequest = PutDocumentsRequest.Builder().addDocuments(note).build() val putFuture = Futures.transformAsync( sessionFuture, { session -> session?.put(putRequest) }, mExecutor ) Futures.addCallback( putFuture, object : FutureCallback<AppSearchBatchResult<String, Void>?> { override fun onSuccess(result: AppSearchBatchResult<String, Void>?) { // Gets map of successful results from Id to Void val successfulResults = result?.successes // Gets map of failed results from Id to AppSearchResult val failedResults = result?.failures } override fun onFailure(t: Throwable) { Log.e(TAG, "Failed to put documents.", t) } }, mExecutor )
Java
Note note = new Note(/*namespace=*/"user1", /*id=*/ "noteId", /*score=*/ 10, /*text=*/ "Buy fresh fruit!"); PutDocumentsRequest putRequest = new PutDocumentsRequest.Builder().addDocuments(note) .build(); ListenableFuture<AppSearchBatchResult<String, Void>> putFuture = Futures.transformAsync(sessionFuture, session -> session.put(putRequest), mExecutor); Futures.addCallback(putFuture, new FutureCallback<AppSearchBatchResult<String, Void>>() { @Override public void onSuccess(@Nullable AppSearchBatchResult<String, Void> result) { // Gets map of successful results from Id to Void Map<String, Void> successfulResults = result.getSuccesses(); // Gets map of failed results from Id to AppSearchResult Map<String, AppSearchResult<Void>> failedResults = result.getFailures(); } @Override public void onFailure(@NonNull Throwable t) { Log.e(TAG, "Failed to put documents.", t); } }, mExecutor);
Telusuri
Anda dapat menelusuri dokumen yang diindeks menggunakan operasi penelusuran yang dibahas di
bagian ini. Kode berikut menjalankan kueri untuk istilah "fruit" di seluruh database untuk dokumen yang termasuk dalam namespace user1.
Kotlin
val searchSpec = SearchSpec.Builder() .addFilterNamespaces("user1") .build(); val searchFuture = Futures.transform( sessionFuture, { session -> session?.search("fruit", searchSpec) }, mExecutor ) Futures.addCallback( searchFuture, object : FutureCallback<SearchResults> { override fun onSuccess(searchResults: SearchResults?) { iterateSearchResults(searchResults) } override fun onFailure(t: Throwable?) { Log.e("TAG", "Failed to search notes in AppSearch.", t) } }, mExecutor )
Java
SearchSpec searchSpec = new SearchSpec.Builder() .addFilterNamespaces("user1") .build(); ListenableFuture<SearchResults> searchFuture = Futures.transform(sessionFuture, session -> session.search("fruit", searchSpec), mExecutor); Futures.addCallback(searchFuture, new FutureCallback<SearchResults>() { @Override public void onSuccess(@Nullable SearchResults searchResults) { iterateSearchResults(searchResults); } @Override public void onFailure(@NonNull Throwable t) { Log.e(TAG, "Failed to search notes in AppSearch.", t); } }, mExecutor);
Melakukan iterasi melalui SearchResults
Penelusuran menampilkan instance SearchResults, yang memberikan akses ke halaman objek SearchResult. Setiap SearchResult
menyimpan GenericDocument yang cocok, yaitu bentuk umum
dokumen yang menjadi tujuan konversi semua dokumen. Kode berikut mendapatkan halaman pertama hasil penelusuran dan mengonversi hasilnya kembali menjadi dokumen Note.
Kotlin
Futures.transform( searchResults?.nextPage, { page: List<SearchResult>? -> // Gets GenericDocument from SearchResult. val genericDocument: GenericDocument = page!![0].genericDocument val schemaType = genericDocument.schemaType val note: Note? = try { if (schemaType == "Note") { // Converts GenericDocument object to Note object. genericDocument.toDocumentClass(Note::class.java) } else null } catch (e: AppSearchException) { Log.e( TAG, "Failed to convert GenericDocument to Note", e ) null } note }, mExecutor )
Java
Futures.transform(searchResults.getNextPage(), page -> { // Gets GenericDocument from SearchResult. GenericDocument genericDocument = page.get(0).getGenericDocument(); String schemaType = genericDocument.getSchemaType(); Note note = null; if (schemaType.equals("Note")) { try { // Converts GenericDocument object to Note object. note = genericDocument.toDocumentClass(Note.class); } catch (AppSearchException e) { Log.e(TAG, "Failed to convert GenericDocument to Note", e); } } return note; }, mExecutor);
Menghapus dokumen
Saat pengguna menghapus catatan, aplikasi akan menghapus dokumen Note
yang sesuai dari database. Tindakan ini memastikan catatan tidak akan lagi muncul dalam kueri. Kode berikut membuat permintaan eksplisit untuk menghapus dokumen Note dari database berdasarkan Id.
Kotlin
val removeRequest = RemoveByDocumentIdRequest.Builder("user1") .addIds("noteId") .build() val removeFuture = Futures.transformAsync( sessionFuture, { session -> session?.remove(removeRequest) }, mExecutor )
Java
RemoveByDocumentIdRequest removeRequest = new RemoveByDocumentIdRequest.Builder("user1") .addIds("noteId") .build(); ListenableFuture<AppSearchBatchResult<String, Void>> removeFuture = Futures.transformAsync(sessionFuture, session -> session.remove(removeRequest), mExecutor);
Menyimpan ke disk
Pembaruan pada database harus dipertahankan secara berkala ke disk dengan memanggil
requestFlush(). Kode berikut memanggil requestFlush() dengan pemroses untuk menentukan apakah panggilan berhasil.
Kotlin
val requestFlushFuture = Futures.transformAsync( sessionFuture, { session -> session?.requestFlush() }, mExecutor ) Futures.addCallback(requestFlushFuture, object : FutureCallback<Void?> { override fun onSuccess(result: Void?) { // Success! Database updates have been persisted to disk. } override fun onFailure(t: Throwable) { Log.e(TAG, "Failed to flush database updates.", t) } }, mExecutor)
Java
ListenableFuture<Void> requestFlushFuture = Futures.transformAsync(sessionFuture, session -> session.requestFlush(), mExecutor); Futures.addCallback(requestFlushFuture, new FutureCallback<Void>() { @Override public void onSuccess(@Nullable Void result) { // Success! Database updates have been persisted to disk. } @Override public void onFailure(@NonNull Throwable t) { Log.e(TAG, "Failed to flush database updates.", t); } }, mExecutor);
Menutup sesi
AppSearchSession
harus ditutup saat aplikasi tidak lagi memanggil operasi
database apa pun. Kode berikut menutup sesi AppSearch yang dibuka
sebelumnya dan mempertahankan semua update ke disk.
Kotlin
val closeFuture = Futures.transform<AppSearchSession, Unit>(sessionFuture, { session -> session?.close() Unit }, mExecutor )
Java
ListenableFuture<Void> closeFuture = Futures.transform(sessionFuture, session -> { session.close(); return null; }, mExecutor);
Referensi lainnya
Untuk mempelajari AppSearch lebih lanjut, lihat referensi tambahan berikut:
Contoh
- Contoh AppSearch Android (Kotlin), aplikasi pencatatan yang menggunakan AppSearch untuk mengindeks catatan pengguna dan memungkinkan pengguna menelusuri catatan mereka.
Berikan masukan
Sampaikan masukan dan ide Anda kepada kami melalui resource berikut:
Laporkan bug agar kami dapat memperbaikinya.