Check out what’s new from Firebase at Google I/O 2022. Learn more

Włączanie funkcji offline w systemie Android

Aplikacje Firebase działać, nawet jeśli aplikacja tymczasowo traci połączenie z siecią. Ponadto Firebase dostarcza narzędzi do utrzymującego dane lokalnie, zarządzania obecności i obsługi utajenia.

Trwałość dysku

Firebase aplikacje automatycznie obsłużyć tymczasowe przerwy w działaniu sieci. Buforowane dane są dostępne w trybie offline i Firebase ponownie wysyła żadnych pisze po przywróceniu połączenia z siecią.

Po włączeniu trwałość dysku, aplikacja zapisuje dane lokalnie na urządzeniu, dzięki czemu aplikacja może utrzymać stan w trybie offline, nawet jeśli użytkownik lub system operacyjny uruchamia ponownie aplikację.

Można włączyć trwałość dysku za pomocą tylko jednego wiersza kodu.

Java

FirebaseDatabase.getInstance().setPersistenceEnabled(true);

Kotlin+KTX

Firebase.database.setPersistenceEnabled(true)

Trwałość Zachowanie

Poprzez umożliwienie wytrwałości, wszelkie dane, które klient Firebase Realtime Database by zsynchronizować gdy ustąpi internetowych na dysku i jest dostępny w trybie offline, nawet gdy użytkownik lub system operacyjny uruchamia ponownie aplikację. Oznacza to, że aplikacja działa tak, że będzie on-line za pomocą lokalnych danych przechowywanych w pamięci podręcznej. callbacks słuchacz nadal ognia lokalnych aktualizacji.

Klient Firebase Realtime Database automatycznie utrzymuje kolejkę wszystkich operacji zapisu, które są wykonywane w czasie, gdy aplikacja jest w trybie offline. Kiedy wytrwałość jest włączona, to kolejka jest również utrzymywały się na dysku więc wszystkich zapisów są dostępne, gdy użytkownik lub system operacyjny uruchamia ponownie aplikację. Gdy aplikacja odzyskuje łączność, wszystkie operacje są wysyłane do serwera Firebase Realtime Database.

Jeśli aplikacja korzysta z uwierzytelniania Firebase klient Firebase Realtime Baza utrzymuje uwierzytelniania użytkownika tokenu całej ponownym uruchomieniu aplikacji. Jeśli auth tokenu wygasa, gdy aplikacja jest w trybie offline, gdy klient wstrzymuje operacje zapisu aż do swojej aplikacji ponownych uwierzytelnia użytkownika, w przeciwnym razie operacje zapisu może się nie powieść ze względu na zasady bezpieczeństwa.

Utrzymywanie danych Fresh

Firebase Realtime bazy danych synchronizuje i przechowuje lokalną kopię danych dla aktywnych słuchaczy. Ponadto, można zachować określone lokalizacje zsynchronizowane.

Java

DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores");
scoresRef.keepSynced(true);

Kotlin+KTX

val scoresRef = Firebase.database.getReference("scores")
scoresRef.keepSynced(true)

Klient Firebase Realtime Database automatycznie pobiera dane w tych miejscach i utrzymuje ją w synchronizacji nawet jeśli odniesienie ma żadnych aktywnych słuchaczy. Można włączyć synchronizację z powrotem wyłączyć za pomocą następującego wiersza kodu.

Java

scoresRef.keepSynced(false);

Kotlin+KTX

scoresRef.keepSynced(false)

Domyślnie 10MB wcześniej zsynchronizowanych danych jest buforowane. To powinno być wystarczające dla większości zastosowań. Jeśli bufor przerasta skonfigurowaną wielkość, Baza Firebase Realtime czyści dane, które zostały użyte przynajmniej ostatnio. Dane, które są przechowywane w synchronizacji nie jest usuwany z pamięci podręcznej.

Pobierania danych offline

Dane Firebase Realtime baza danych przechowuje wrócił z zapytaniem do użytku w trybie offline. W przypadku pytań skonstruowanych w trybie offline, Baza Firebase Realtime kontynuuje pracę na wcześniej załadowanych danych. Jeżeli żądane dane nie zostały załadowane na Firebase Realtime obciążenia bazy danych z lokalnej pamięci podręcznej. Gdy łączność sieciowa jest ponownie dostępny, ładunki danych i będzie odzwierciedlać zapytania.

Na przykład, ten kod zapytań w ciągu ostatnich czterech pozycji w bazie danych Firebase Realtime partytur

Java

DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores");
scoresRef.orderByValue().limitToLast(4).addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(@NonNull DataSnapshot snapshot, String previousChild) {
        Log.d(TAG, "The " + snapshot.getKey() + " dinosaur's score is " + snapshot.getValue());
    }

    // ...
});

Kotlin+KTX

val scoresRef = Firebase.database.getReference("scores")
scoresRef.orderByValue().limitToLast(4).addChildEventListener(object : ChildEventListener {
    override fun onChildAdded(snapshot: DataSnapshot, previousChild: String?) {
        Log.d(TAG, "The ${snapshot.key} dinosaur's score is ${snapshot.value}")
    }

    // ...
})

Załóżmy, że użytkownik traci połączenie, przechodzi w tryb offline i ponownie uruchamia aplikację. W trybie offline, aplikacja wysyła zapytanie do dwóch ostatnich pozycji z tej samej lokalizacji. To zapytanie zostanie pomyślnie powrócić ostatnie dwie pozycje, ponieważ aplikacja już załadowane wszystkie cztery elementy w kwerendzie powyżej.

Java

scoresRef.orderByValue().limitToLast(2).addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(@NonNull DataSnapshot snapshot, String previousChild) {
        Log.d(TAG, "The " + snapshot.getKey() + " dinosaur's score is " + snapshot.getValue());
    }

    // ...
});

Kotlin+KTX

scoresRef.orderByValue().limitToLast(2).addChildEventListener(object : ChildEventListener {
    override fun onChildAdded(snapshot: DataSnapshot, previousChild: String?) {
        Log.d(TAG, "The ${snapshot.key} dinosaur's score is ${snapshot.value}")
    }

    // ...
})

W poprzednim przykładzie, Firebase Realtime podnosi klienta bazy danych „dziecko dodana” imprezy dla najwyższej punktacji dwóch dinozaurów, używając utrzymywały cache. Ale to nie podniesie zdarzenie „wartość”, ponieważ aplikacja nie została wykonana, że zapytania w trybie online.

Jeśli aplikacja miała zażądać ostatnie sześć pozycji w trybie offline, to get „dziecko” dodaje imprezy dla czterech buforowanych pozycji od razu. Gdy urządzenie powróci do trybu online, klient Firebase Realtime Database synchronizuje się z serwerem i pobiera dwa ostatnie „dziecko dodanej” i „wartości” zdarzenia z aplikacji.

Obsłudze transakcji Offline

Wszelkie transakcje, które są wykonywane podczas gdy aplikacja jest w trybie offline, są ustawiane w kolejce. Gdy odzyskuje łączności sieciowej aplikacji, transakcje są wysyłane do serwera bazy danych w czasie rzeczywistym.

zarządzanie Obecność

W aplikacjach czasu rzeczywistego często jest przydatna do wykrywania kiedy klienci połączyć i rozłączyć. Na przykład, może chcesz oznaczyć użytkownika jako „” w trybie offline, gdy ich rozłącza klienta.

Firebase klienci bazy danych dostarczają prostych prymitywów, które można wykorzystać do zapisu w bazie danych, gdy rozłącza klienta z serwerami Firebase Database. Aktualizacje te występują czy rozłącza klienta czysto czy nie, dzięki czemu można na nich polegać, aby oczyścić dane, nawet jeśli połączenie zostanie upuszczony lub klient wywala. Wszystkie operacje zapisu, w tym ustawieniu, aktualizowania i usuwania, mogą być wykonywane na odłączenie.

Oto prosty przykład zapisu danych po odłączeniu przy użyciu onDisconnect prymitywne:

Java

DatabaseReference presenceRef = FirebaseDatabase.getInstance().getReference("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().setValue("I disconnected!");

Kotlin+KTX

val presenceRef = Firebase.database.getReference("disconnectmessage")
// Write a string when this client loses connection
presenceRef.onDisconnect().setValue("I disconnected!")

Jak onDisconnect Works

Podczas nawiązywania onDisconnect() operacji, operacja mieszka na serwerze Firebase Realtime Database. Zabezpieczenie serwer sprawdza, aby upewnić się, że użytkownik może wykonać zdarzenie zapisu wniosek i informuje swoją aplikację, jeżeli jest ona nieważna. Następnie serwer monitoruje połączenia. Jeśli w dowolnym momencie czasy połączeń, lub jest aktywnie zamknięty przez klienta w czasie rzeczywistym danych, bezpieczeństwo Serwer sprawdza po raz drugi (aby upewnić się, że operacja jest nadal ważne), a następnie wywołuje zdarzenie.

Twoja aplikacja może użyć wywołania zwrotnego na operację zapisu w celu zapewnienia onDisconnect został prawidłowo podłączony:

Java

presenceRef.onDisconnect().removeValue(new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError error, @NonNull DatabaseReference reference) {
        if (error != null) {
            Log.d(TAG, "could not establish onDisconnect event:" + error.getMessage());
        }
    }
});

Kotlin+KTX

presenceRef.onDisconnect().removeValue { error, reference ->
    error?.let {
        Log.d(TAG, "could not establish onDisconnect event: ${error.message}")
    }
}

onDisconnect zdarzenie może być również anulowana przez wywołanie .cancel() :

Java

OnDisconnect onDisconnectRef = presenceRef.onDisconnect();
onDisconnectRef.setValue("I disconnected");
// ...
// some time later when we change our minds
// ...
onDisconnectRef.cancel();

Kotlin+KTX

val onDisconnectRef = presenceRef.onDisconnect()
onDisconnectRef.setValue("I disconnected")
// ...
// some time later when we change our minds
// ...
onDisconnectRef.cancel()

Wykrywanie stanu połączenia

Dla wielu cech obecności związane jest przydatna aplikacja wiedzieć, kiedy jest to online lub offline. Firebase Realtime Database zapewnia specjalną lokalizację na /.info/connected który jest aktualizowany za każdym razem zmienia stan połączenia bazy danych klienta Firebase czasie rzeczywistym. Oto przykład:

Java

DatabaseReference connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        boolean connected = snapshot.getValue(Boolean.class);
        if (connected) {
            Log.d(TAG, "connected");
        } else {
            Log.d(TAG, "not connected");
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        Log.w(TAG, "Listener was cancelled");
    }
});

Kotlin+KTX

val connectedRef = Firebase.database.getReference(".info/connected")
connectedRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        val connected = snapshot.getValue(Boolean::class.java) ?: false
        if (connected) {
            Log.d(TAG, "connected")
        } else {
            Log.d(TAG, "not connected")
        }
    }

    override fun onCancelled(error: DatabaseError) {
        Log.w(TAG, "Listener was cancelled")
    }
})

/.info/connected jest wartość logiczna, która nie jest zsynchronizowana między klientami Realtime baz danych, ponieważ wartość jest zależna od stanu klienta. Innymi słowy, jeśli jeden klient czyta /.info/connected jako fałszywe, to nie ma gwarancji, że oddzielny klient będzie również odczytać fałszywe.

Na Androidzie Firebase automatycznie zarządza stan połączenia zmniejszyć przepustowość i wykorzystanie baterii. Gdy klient ma żadnych aktywnych słuchaczy nie oczekującą pisać lub onDisconnect operacji, i nie jest wyraźnie odłączony przez goOffline metodzie Firebase zamyka połączenie po 60 sekundach bezczynności.

Obchodzenie Latency

serwer Sygnatury

Serwery Firebase Realtime Database zapewnić mechanizm wstawiania znaczników czasu generowane na serwerze jako danych. Funkcja ta, w połączeniu z onDisconnect , zapewnia łatwy sposób wiarygodny zanotuj czas, w którym klient bazy danych w czasie rzeczywistym odłączonym:

Java

DatabaseReference userLastOnlineRef = FirebaseDatabase.getInstance().getReference("users/joe/lastOnline");
userLastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP);

Kotlin+KTX

val userLastOnlineRef = Firebase.database.getReference("users/joe/lastOnline")
userLastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP)

Clock Skew

Choć firebase.database.ServerValue.TIMESTAMP jest znacznie bardziej dokładne i odpowiednie dla większości operacji odczytu / zapisu, może czasami być przydatne do oszacowania zegar klienta skośna w stosunku do serwerów bazy danych w czasie rzeczywistym za Firebase. Można dołączyć wywołania zwrotnego do lokalizacji /.info/serverTimeOffset aby uzyskać wartość w milisekundach, że klienci Firebase Realtime Database dodać do lokalnego czasu zgłosił (czas epoki w milisekundach), aby oszacować czas serwera. Zauważ, że to przesunięcie na dokładność może mieć wpływ na opóźnienia w sieci, a więc jest przydatny głównie do odkrywania dużych (> 1 sekunda) rozbieżności w czasie zegara.

Java

DatabaseReference offsetRef = FirebaseDatabase.getInstance().getReference(".info/serverTimeOffset");
offsetRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        double offset = snapshot.getValue(Double.class);
        double estimatedServerTimeMs = System.currentTimeMillis() + offset;
    }

    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        Log.w(TAG, "Listener was cancelled");
    }
});

Kotlin+KTX

val offsetRef = Firebase.database.getReference(".info/serverTimeOffset")
offsetRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        val offset = snapshot.getValue(Double::class.java) ?: 0.0
        val estimatedServerTimeMs = System.currentTimeMillis() + offset
    }

    override fun onCancelled(error: DatabaseError) {
        Log.w(TAG, "Listener was cancelled")
    }
})

Sample Obecność App

Łącząc operacje odłączania z monitorujących stan połączenia i serwera znaczników czasu, można zbudować system obecność użytkownika. W tym systemie każdy użytkownik przechowuje dane w miejscu bazy danych, aby wskazać, czy klient Realtime Baza jest online. Klienci ustawić tę lokalizację true gdy przychodzą online i znacznik czasu, kiedy się rozłączyć. Ten znacznik czasu wskazuje czas ostatniej dany użytkownik został Internecie.

Należy pamiętać, że aplikacja powinna kolejce operacji odłączania zanim użytkownik jest oznaczony w trybie online, aby uniknąć warunków wyścigu w przypadku połączenia sieciowego klienta jest stracone, zanim obie komendy mogą być przesyłane do serwera.

Oto prosty system obecność użytkownika:

Java

// Since I can connect from multiple devices, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
final FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference myConnectionsRef = database.getReference("users/joe/connections");

// Stores the timestamp of my last disconnect (the last time I was seen online)
final DatabaseReference lastOnlineRef = database.getReference("/users/joe/lastOnline");

final DatabaseReference connectedRef = database.getReference(".info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot snapshot) {
        boolean connected = snapshot.getValue(Boolean.class);
        if (connected) {
            DatabaseReference con = myConnectionsRef.push();

            // When this device disconnects, remove it
            con.onDisconnect().removeValue();

            // When I disconnect, update the last time I was seen online
            lastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP);

            // Add this device to my connections list
            // this value could contain info about the device or a timestamp too
            con.setValue(Boolean.TRUE);
        }
    }

    @Override
    public void onCancelled(DatabaseError error) {
        Log.w(TAG, "Listener was cancelled at .info/connected");
    }
});

Kotlin+KTX

// Since I can connect from multiple devices, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
val database = Firebase.database
val myConnectionsRef = database.getReference("users/joe/connections")

// Stores the timestamp of my last disconnect (the last time I was seen online)
val lastOnlineRef = database.getReference("/users/joe/lastOnline")

val connectedRef = database.getReference(".info/connected")
connectedRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        val connected = snapshot.getValue<Boolean>() ?: false
        if (connected) {
            val con = myConnectionsRef.push()

            // When this device disconnects, remove it
            con.onDisconnect().removeValue()

            // When I disconnect, update the last time I was seen online
            lastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP)

            // Add this device to my connections list
            // this value could contain info about the device or a timestamp too
            con.setValue(java.lang.Boolean.TRUE)
        }
    }

    override fun onCancelled(error: DatabaseError) {
        Log.w(TAG, "Listener was cancelled at .info/connected")
    }
})