关于android:FirebaseDatabase.getInstance()。setPersistenceEnabled(true)真正做什么?

What does FirebaseDatabase.getInstance().setPersistenceEnabled(true) really do?

我似乎不喜欢setPersistenceEnabled。

我以为是

1
FirebaseDatabase.getInstance().setPersistenceEnabled(true);

作为我Android应用程序对象中的第一件事,即使在飞行模式下,我也可以在本地读取和写入Firebase数据,并且我的数据将存储在本地,因此即使在飞行模式下,下一次启动应用程序时,我的数据也将可用。

我以为应用程序脱机时所做的写操作将在网络再次可用时与FB数据库同步。

事实并非如此。

[编辑]
飞行模式下的写入已完成,但该数据似乎无法读取。

addListenerForSingleValueEvent和ValueEventListener不会在没有网络的情况下检测数据库写入。

有人可以帮我了解setPersistenceEnabled(true)的作用,以及它的典型用例是什么?

编辑添加:

我写了我能想到的最小的Android Firebase数据库应用程序。

这是应用程序类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 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");
    }
}

所有主要活动是在EditText旁边显示一个"保存"按钮。
在onCreate MainActivity中,登录一个已知用户。然后,当用户单击"保存"按钮时,EditText中的字符串将写入Firebase。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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);
    }
}

只要设备连接到网络,这一切都可以工作。

如果应用程序在没有网络连接的情况下启动,则登录失败,因此用户无法执行任何操作。

如果在应用运行时网络连接断开,则当网络恢复时,将不会保存任何已保存的字符串并将其上传到Firebase。

这是预期的行为吗?此行为似乎与下面引用的文档不一致:

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.


我的问题很简单。 即使我拥有TheApp类,我也忘记了更新清单,以便首先调用TheApp。 您可以使用"名称"应用程序标签来执行此操作:

1
2
3
4
5
6
7
<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! -->

现在,由于实际上正在调用setPersistenceEnabled(true),因此该应用程序似乎可以在脱机状态下正常运行。 唯一的限制是,如果您注销然后失去网络,则无法进行身份验证。 但是看来,如果您通过了身份验证,则即使重新启动应用程序,它也可以脱机工作。 至少看起来是这样。