AppSearch

AppSearch to wydajne rozwiązanie do wyszukiwania na urządzeniu, które umożliwia zarządzanie uporządkowanymi danymi przechowywanymi lokalnie. Zawiera interfejsy API do indeksowania i pobierania danych za pomocą wyszukiwania pełnotekstowego. Aplikacje mogą używać AppSearch do oferowania niestandardowych funkcji wyszukiwania w aplikacji, dzięki czemu użytkownicy mogą wyszukiwać treści nawet w trybie offline.

Diagram przedstawiający indeksowanie i wyszukiwanie w AppSearch

AppSearch oferuje te funkcje:

  • szybka implementacja pamięci masowej zoptymalizowana pod kątem urządzeń mobilnych i małego wykorzystania operacji wejścia-wyjścia;
  • Bardzo wydajne indeksowanie i wykonywanie zapytań na dużych zbiorach danych.
  • obsługę wielu języków, np. angielskiego i hiszpańskiego;
  • Ranking trafności i ocena wykorzystania

Dzięki mniejszemu wykorzystaniu operacji wejścia/wyjścia AppSearch zapewnia mniejsze opóźnienia podczas indeksowania i wyszukiwania w dużych zbiorach danych w porównaniu z SQLite. AppSearch upraszcza zapytania dotyczące różnych typów, obsługując pojedyncze zapytania, podczas gdy SQLite scala wyniki scalone z wielu tabel.

Aby zilustrować funkcje AppSearch, weźmy przykład aplikacji muzycznej, która zarządza ulubionymi utworami użytkowników i umożliwia im łatwe wyszukiwanie. Użytkownicy słuchają muzyki z całego świata, a tytuły utworów są w różnych językach. AppSearch natywnie obsługuje indeksowanie i wysyłanie zapytań w tych językach. Gdy użytkownik wyszukuje utwór według tytułu lub nazwy wykonawcy, aplikacja po prostu przekazuje żądanie do AppSearch, aby szybko i skutecznie pobrać pasujące utwory. Aplikacja wyświetla wyniki, dzięki czemu użytkownicy mogą szybko zacząć odtwarzać ulubione utwory.

Konfiguracja

Aby używać AppSearch w aplikacji, dodaj do jej pliku build.gradle te zależności:

Odlotowe

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")

}

Pojęcia związane z AppSearch

Poniższy diagram przedstawia pojęcia związane z AppSearch i ich interakcje.

Diagram przedstawiający aplikację kliencką i jej interakcje z tymi pojęciami związanymi z AppSearch: baza danych AppSearch, schemat, typy schematów, dokumenty, sesja i wyszukiwanie. Rysunek 1. Diagram pojęć związanych z AppSearch: baza danych AppSearch, schemat, typy schematów, dokumenty, sesja i wyszukiwanie.

Baza danych i sesja

Baza danych AppSearch to kolekcja dokumentów zgodna ze schematem bazy danych. Aplikacje klienckie tworzą bazę danych, podając kontekst aplikacji i nazwę bazy danych. Bazy danych mogą być otwierane tylko przez aplikację, która je utworzyła. Po otwarciu bazy danych zwracana jest sesja umożliwiająca interakcję z bazą danych. Sesja jest punktem wejścia do wywoływania interfejsów API AppSearch i pozostaje otwarta, dopóki nie zostanie zamknięta przez aplikację kliencką.

Schemat i typy schematów

Schemat reprezentuje strukturę organizacyjną danych w bazie danych AppSearch.

Schemat składa się z typów schematów, które reprezentują unikalne typy danych. Typy schematów składają się z właściwości, które zawierają nazwę, typ danych i liczność. Po dodaniu typu schematu do schematu bazy danych można tworzyć dokumenty tego typu i dodawać je do bazy danych.

Dokumenty

W AppSearch jednostka danych jest reprezentowana jako dokument. Każdy dokument w bazie danych AppSearch jest jednoznacznie identyfikowany przez przestrzeń nazw i identyfikator. Przestrzenie nazw służą do oddzielania danych z różnych źródeł, gdy zapytanie ma dotyczyć tylko jednego źródła, np. kont użytkowników.

Dokumenty zawierają sygnaturę czasową utworzenia, czas życia (TTL) i wynik, który może być używany do rankingu podczas pobierania. Do dokumentu jest też przypisany typ schematu, który opisuje dodatkowe właściwości danych, które musi mieć dokument.

Klasa dokumentu to abstrakcja dokumentu. Zawiera on pola z adnotacjami, które reprezentują zawartość dokumentu. Domyślnie nazwa klasy dokumentu określa nazwę typu schematu.

Dokumenty są indeksowane i można je wyszukiwać, podając zapytanie. Dokument jest dopasowywany i uwzględniany w wynikach wyszukiwania, jeśli zawiera słowa z zapytania lub pasuje do innej specyfikacji wyszukiwania. Wyniki są uporządkowane na podstawie wyniku i strategii rankingu. Wyniki wyszukiwania są reprezentowane przez strony, które można pobierać sekwencyjnie.

AppSearch oferuje dostosowywanie wyszukiwania, np. filtry, konfigurację rozmiaru strony i fragmenty kodu.

pamięć platformy, pamięć lokalna lub pamięć Usług Google Play;

AppSearch oferuje 3 rozwiązania do przechowywania danych: LocalStorage, PlatformStorage i PlayServicesStorage. W przypadku LocalStorage aplikacja zarządza indeksem, który znajduje się w katalogu danych aplikacji. Dzięki PlatformStorage i PlayServicesStorage aplikacja współtworzy centralny indeks całego systemu. Indeks aplikacji PlatformStorage jest hostowany na serwerze systemowym, a indeks aplikacji PlayServicesStorage – w pamięci Usług Google Play. Dostęp do danych w tych indeksach centralnych jest ograniczony do danych, które zostały przesłane przez Twoją aplikację, oraz danych, które zostały wyraźnie udostępnione przez inną aplikację. Wszystkie te opcje pamięci masowej korzystają z tego samego interfejsu API i można je wymieniać w zależności od wersji urządzenia.

Pamiętaj, że obsługa funkcji różni się w zależności od opcji miejsca na dane i urządzenia. Więcej informacji znajdziesz w artykule Sprawdzanie dostępności funkcji.

Ten kod tworzy sesję PlatformStorage na Androidzie 12 (API na poziomie 31) lub nowszym oraz sesję PlayServicesStorage lub LocalStorage we wcześniejszych wersjach:

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()));
    }
}

Dzięki PlatformStorage i PlayServicesStorage Twoja aplikacja może bezpiecznie udostępniać dane innym aplikacjom, aby mogły one również wyszukiwać dane Twojej aplikacji. Udostępnianie danych aplikacji tylko do odczytu jest przyznawane za pomocą uzgadniania certyfikatu, aby upewnić się, że druga aplikacja ma uprawnienia do odczytu danych. Więcej informacji o tym interfejsie API znajdziesz w dokumentacji setSchemaTypeVisibilityForPackage().

Dodatkowo dzięki PlatformStorage zindeksowane dane mogą być wyświetlane na powierzchniach interfejsu systemu. Aplikacje mogą zrezygnować z wyświetlania niektórych lub wszystkich danych w interfejsie systemu. Więcej informacji o tym interfejsie API znajdziesz w dokumentacji setSchemaTypeDisplayedBySystem().

Funkcje LocalStorage (zgodna z Androidem 5.0 lub nowszym) PlatformStorage (zgodne z Androidem 12 lub nowszym) PlayServicesStorage (zgodna z Androidem 5.0 lub nowszym)
efektywne wyszukiwanie pełnotekstowe,
Obsługa wielu języków
mniejszy rozmiar pliku binarnego,
Udostępnianie danych między aplikacjami
Możliwość wyświetlania danych na platformach interfejsu systemu
Można indeksować nieograniczoną liczbę dokumentów o dowolnym rozmiarze.
Szybsze operacje bez dodatkowego czasu oczekiwania na binder

Wybierając między LocalStorage a PlatformStorage, należy wziąć pod uwagę dodatkowe kompromisy. PlatformStorage opakowuje interfejsy API Jetpacka w usługę systemową AppSearch, więc wpływ na rozmiar pliku APK jest minimalny w porównaniu z użyciem LocalStorage. Oznacza to jednak, że operacje AppSearch powodują dodatkowe opóźnienie binder podczas wywoływania usługi systemowej AppSearch. W przypadku PlatformStorage AppSearch ogranicza liczbę i rozmiar dokumentów, które aplikacja może indeksować, aby zapewnić wydajny indeks centralny. PlayServicesStorage ma też takie same ograniczenia jak PlatformStorage i jest obsługiwany tylko na urządzeniach z usługami Google Play.

Sprawdzanie dostępności funkcji

Chociaż wszystkie opcje pamięci masowej korzystają z tego samego interfejsu API, niektóre funkcje nie są dostępne we wszystkich opcjach pamięci masowej ani na wszystkich urządzeniach. W dokumentacji interfejsu API adnotacja @RequiresFeature identyfikuje interfejsy API, które wymagają jednej z tych funkcji, a klasa Features definiuje stałą dla każdej funkcji. Na przykład: INDEXING_TYPE_RANGE wymaga Features.NUMERIC_SEARCH.

W przypadku PlatformStorage obsługa funkcji zależy od wersji Androida na urządzeniu. Począwszy od Androida 13 (poziom interfejsu API 33), obsługa funkcji zależy też od aktualizacji systemowych Google Play, które otrzymało urządzenie. Na przykład PlatformStorage obsługuje wyszukiwanie numeryczne (Features.NUMERIC_SEARCH), wyszukiwanie dosłowne (Features.VERBATIM_SEARCH) i łączenie (Features.JOIN_SPEC_AND_QUALIFIED_ID) tylko na tych urządzeniach:

  • urządzenia z Androidem 14 (poziom API 34) lub nowszym;
  • urządzenia z Androidem 13 (poziom interfejsu API 33), które otrzymały wymaganą aktualizację systemową Google Play;

Te funkcje nie są obsługiwane na urządzeniach z Androidem 12 lub Androidem 12L (poziomy interfejsu API 31 i 32).

Maksymalna liczba indeksowanych właściwości w dokumencie również różni się w zależności od urządzenia i opcji miejsca na dane. Aby uzyskać limit w czasie działania, wywołaj getMaxIndexedProperties().

Nie polegaj wyłącznie na wersji Androida, aby określić, czy funkcja jest obsługiwana. Zanim wywołasz interfejs API, który wymaga danej funkcji, sprawdź, czy jest ona obsługiwana, wywołując metodę isFeatureSupported() na obiekcie Features zwracanym przez AppSearchSession.getFeatures(). Jeśli wymagana funkcja nie jest obsługiwana, operacja nie powiedzie się i zostanie zgłoszony wyjątek. Przykładem niepowodzenia jest ustawienie schematu, który zawiera właściwość INDEXING_TYPE_RANGE, na urządzeniach, które nie obsługują Features.NUMERIC_SEARCH.

Poniższy kod sprawdza, czy otwarty AppSearchSession obsługuje wyszukiwanie numeryczne:

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

Pierwsze kroki z AppSearch

Przykład w tej sekcji pokazuje, jak używać interfejsów API AppSearch do integracji z hipotetyczną aplikacją do robienia notatek.

Zapisywanie klasy dokumentu

Pierwszym krokiem integracji z AppSearch jest napisanie klasy dokumentu, która opisuje dane do wstawienia do bazy danych. Oznacz klasę jako klasę dokumentu za pomocą adnotacji @Document.Możesz używać instancji klasy dokumentu, aby umieszczać dokumenty w bazie danych i pobierać je z niej.

Poniższy kod definiuje klasę dokumentu Note z polem oznaczonym jako @Document.StringProperty do indeksowania tekstu obiektu 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;
  }
}

Otwieranie bazy danych

Zanim zaczniesz pracować z dokumentami, musisz utworzyć bazę danych. Poniższy kod tworzy nową bazę danych o nazwie notes_app i pobiera ListenableFuture dla AppSearchSession, który reprezentuje połączenie z bazą danych i udostępnia interfejsy API do operacji na bazie danych.

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()
);

Ustawianie schematu

Zanim będzie można umieszczać dokumenty w bazie danych i pobierać je z niej, musisz ustawić schemat. Schemat bazy danych składa się z różnych typów uporządkowanych danych, nazywanych „typami schematu”. Poniższy kod ustawia schemat, podając klasę dokumentu jako typ schematu.

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);

Umieszczanie dokumentu w bazie danych

Po dodaniu typu schematu możesz dodawać do bazy danych dokumenty tego typu. Poniższy kod tworzy dokument typu schematu Note za pomocą kreatora klasy dokumentu Note. Ustawia przestrzeń nazw dokumentu user1, aby reprezentowała dowolnego użytkownika tej próbki. Następnie dokument jest wstawiany do bazy danych i dołączany jest detektor, który przetwarza wynik operacji umieszczania.

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);

Możesz wyszukiwać dokumenty, które są indeksowane, korzystając z operacji wyszukiwania opisanych w tej sekcji. Poniższy kod wyszukuje w bazie danych termin „fruit” w dokumentach należących do przestrzeni nazw 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);

Iterowanie po SearchResults

Wyszukiwania zwracają instancję SearchResults, która zapewnia dostęp do stron obiektów SearchResult. Każdy element SearchResult zawiera dopasowany element GenericDocument, czyli ogólną formę dokumentu, na którą są konwertowane wszystkie dokumenty. Podany niżej kod pobiera pierwszą stronę wyników wyszukiwania i konwertuje wynik z powrotem na dokument 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);

Usuwanie dokumentu

Gdy użytkownik usunie notatkę, aplikacja usunie odpowiedni dokument Note z bazy danych. Dzięki temu notatka nie będzie już wyświetlana w zapytaniach. Poniższy kod wysyła wyraźne żądanie usunięcia dokumentu Note z bazy danych według identyfikatora.

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);

Trwale przechowuj na dysku

Aktualizacje bazy danych powinny być okresowo zapisywane na dysku przez wywołanie metody requestFlush(). Poniższy kod wywołuje metodę requestFlush() z detektorem, aby określić, czy wywołanie się powiodło.

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);

Zamykanie sesji

Obiekt AppSearchSession należy zamknąć, gdy aplikacja nie będzie już wywoływać żadnych operacji na bazie danych. Poniższy kod zamyka otwartą wcześniej sesję AppSearch i zapisuje wszystkie aktualizacje na dysku.

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);

Dodatkowe materiały

Więcej informacji o AppSearch znajdziesz w tych materiałach:

Przykłady

Prześlij opinię

Podziel się z nami swoją opinią i pomysłami, korzystając z tych materiałów:

Narzędzie Issue Tracker

Zgłaszaj błędy, abyśmy mogli je naprawić.