I don't seem to grok setPersistenceEnabled.
I had thought that by calling
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
as the first thing in my Android app object that I could read and write Firebase data locally even in airplane mode, and that my data would be stored locally and would therefore be available the next time the app starts, even in airplane mode.
I thought writes made while the app was offline would synch with the FB database when the network became available again.
That doesn't seem the case at all.
[edited] Writes in airplane mode complete, but that data doesn't seem to available to read.
addListenerForSingleValueEvent and ValueEventListener do not detect database writes with no network.
Can someone please help me understand what setPersistenceEnabled(true) does, and what typical use cases for for it might be?
Edited to add:
I wrote the smallest possible Android Firebase database app I could think of.
Here's the app class:
import android.app.Application;
import android.util.Log;
import com.google.firebase.database.FirebaseDatabase;
public class TheApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// See https://firebase.google.com/docs/reference/android/com/google/firebase/database/FirebaseDatabase.html#public-methods
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
Log.d("TheApp", "application created");
}
}
All the main activity does is display a 'save' button next to an EditText. In onCreate MainActivity logs in a know user. When the user then clicks the save button the string in the EditText is written to Firebase.
package com.grayraven.simpledb;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
public class MainActivity extends AppCompatActivity {
FirebaseAuth mAuth;
FirebaseUser mUser;
ValueEventListener mListener;
private FirebaseAuth.AuthStateListener mAuthListener;
private static final String TAG = "Main";
FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference dbRef;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
dbRef = db.getReference("/data/strings/");
Button btnSave = (Button)findViewById(R.id.btn_save);
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText editText = (EditText)findViewById(R.id.editText);
String text = String.valueOf(editText.getText());
dbRef.setValue(text);
}
});
signIn();
}
private void signIn() {
mAuth= FirebaseAuth.getInstance();
String email = "[email protected]"; //valid credentials
String password = "12345678";
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithEmail:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
//always fails when offline
Log.w(TAG, "signInWithEmail failed", task.getException());
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
This all works as long as the device is connected to the net.
If the app starts with no network connect the login fails, so the user can do nothing.
If the network connection drops while the app is running no saved strings are preserved and uploaded to Firebase when the network comes back.
Is this expected behavior? This behavior doesn't seem consistent with the documentation quoted below:
public synchronized void setPersistenceEnabled (boolean isEnabled)
The Firebase Database client will cache synchronized data and keep track of all writes you've initiated while your application is running. It seamlessly handles intermittent network connections and re-sends write operations when the network connection is restored. However by default your write operations and cached data are only stored in-memory and will be lost when your app restarts. By setting this value to
true, the data will be persisted to on-device (disk) storage and will thus be available again when the app is restarted (even when there is no network connectivity at that time). Note that this method must be called before creating your first Database reference and only needs to be called once per application.
My problem was really simple. Even though I had my TheApp class, I forgot to update the manifest such that TheApp would be called first. You do that with the 'name' application tag:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name="com.grayraven.simpledb.TheApp"> <!-- I forgot this! -->
Now the app seems to work fine on or offline since setPersistenceEnabled(true) is actually being called. The only limitation is that you can't authenticate if you logged off and then lost your network. But it appears that if you were authenticated your app will work offline, even if you restart it. At least that appears to be the case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With