我正在创建我的第一个Firebase应用。它的一个要求是它在网络不可用时运行。 Firebase指南指出:
启用磁盘持久性使我们的应用程序即使在应用程序重新启动后也能保持其所有状态。我们只需一行代码即可启用磁盘持久性。 的 FirebaseDatabase.getInstance()setPersistenceEnabled(真); 启用磁盘持久性后,我们的同步数据和写入将在应用程序重新启动后持久保存到磁盘,我们的应用程序应在脱机情况下无缝工作。
另一项要求是使用Google登录。因此,在我的MainActivity
中,我会检查用户是否已登录,如果没有,我会启动SignInActivity
。 (SignInActivity
来自Firebase示例。)SignInActivity
有效,用户登录,MainActivity
第二次启动。现在,我的应用程序在代码行FirebaseDatabase.getInstance().setPersistenceEnabled(true);
上崩溃,并显示以下消息:
必须在使用FirebaseDatabase实例之前调用setPersistenceEnabled()。
现在,如果我重新启动我的应用,用户已登录,SignInActivity
未启动,我的应用运行正常。
在用户登录后如何避免此崩溃的任何建议?
在发布此问题时,我收到了重新安置FirebaseDatabase.getInstance().setPersistenceEnabled(true);
的建议
到我的“应用程序类”。我得到完全相同的结果...... SignInActivity
启动,完成,我在setPersistenceEnabled
上崩溃。
以下是我的MainActivity onCreate
:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Calls to setPersistenceEnabled() must be made before any other usage of FirebaseDatabase instance.
// Crash here upon returning from SignInActivity.
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
mFirebaseDbReference = FirebaseDatabase.getInstance().getReference();
// Initialize Firebase Auth
mFirebaseAuth = FirebaseAuth.getInstance();
mFirebaseUser = mFirebaseAuth.getCurrentUser();
if (mFirebaseUser == null) {
// Not signed in, launch the Sign In activity
Timber.tag("MainActivity").i("onCreate(): User not signed in, launching SignInActivity");
startActivity(new Intent(this, SignInActivity.class));
finish();
} else {
mUsername = mFirebaseUser.getDisplayName();
Timber.tag("MainActivity").i("onCreate(): User \"%s\" signed in.", mUsername);
if (mFirebaseUser.getPhotoUrl() != null) {
mPhotoUrl = mFirebaseUser.getPhotoUrl().toString();
}
}
答案 0 :(得分:50)
FirebaseApp由ContentProvider
初始化,因此在调用onCreate()
时未初始化。
像这样获取您的FirebaseDatabase:
public class Utils {
private static FirebaseDatabase mDatabase;
public static FirebaseDatabase getDatabase() {
if (mDatabase == null) {
mDatabase = FirebaseDatabase.getInstance();
mDatabase.setPersistenceEnabled(true);
}
return mDatabase;
}
}
然后从您想要的任何活动中拨打Utils.getDatabase()
。
答案 1 :(得分:46)
我在setPersistenceEnabled(true)
课程中使用Application
修复了此异常。
public class MApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
}
在AndroidManifest.xml中,将应用程序名称设置为MApplication:
<application
android:name=".MApplication"
... />
答案 2 :(得分:25)
我遇到了类似的问题,使用静态变量似乎解决了我的问题。所以起初我的代码看起来像这样
@Override
protected void onCreate(Bundle savedInstanceState) {
//..code
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
FirebaseDatabase database = FirebaseDatabase.getInstance();
//..code
}
现在看起来更像是
static boolean calledAlready = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
//..code
if (!calledAlready)
{
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
calledAlready = true;
}
FirebaseDatabase database = FirebaseDatabase.getInstance();
//..code
}
希望它有所帮助!
答案 3 :(得分:15)
我有点迟了但今天我遇到了这个问题,我通过添加
来解决static {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
到我的活动
答案 4 :(得分:3)
对我而言,通过为Firebase创建单独的类更容易处理。这是因为Firebase有自己的实例,如果您在多个活动中使用它,如果您在另一个活动中再次调用setPersistenceEnabled,则可能会崩溃。
另一个好处是,如果需要,您可以将您的上下文或参数传递给FirebaseHandler构造函数。或者,如果您在数据库中有固定位置,则可以在没有.child(&#34; location&#34;)样板的情况下轻松调用它们。
实施例:
public class FirebaseHandler {
// parameters
private Context context;
private String userKey;
private DatabaseReference databaseReference;
private static boolean isPersistenceEnabled = false;
private static String fixedLocationA = "locationA";
private static String fixedLocationB = "locationB";
public FirebaseHandler(Context context, String userKey) {
this.context = context; // context can be used to call PreferenceManager etc.
this.userKey = userKey;
if (!isPersistenceEnabled) {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
isPersistenceEnabled = true;
}
databaseReference = FirebaseDatabase.getInstance().getReference().child(userKey);
}
public DatabaseReference getRefA() {
return databaseReference.child(fixedLocationA);
}
public DatabaseReference getRefB() {
return databaseReference.child(fixedLocationB);
}
}
然后可以在任何活动中调用它,如下所示。
public class MyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get instance
FirebaseHandler firebaseHandler = new FirebaseHander(this, "userKey");
// to set value
firebaseHandler.getRefA().setValue("value");
// to set listener
firebaseHandler.getRefB().addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// TODO here....
// also, can remove listener if required
if (certain condition) {
firebaseHandler.getRefB().removeEventListener(this);
}
}
}
}
}
答案 5 :(得分:1)
通过使Firebase引用成为这样的静态类字段来解决它:
public class MainActivity extends AppCompatActivity
private static FirebaseDatabase fbDatabase;
@Override
protected void onCreate(Bundle savedInstanceState) {
if(fbDatabase == null) {
fbDatabase = FirebaseDatabase.getInstance();
fbDatabase.setPersistenceEnabled(true);
}
在其他活动中创建新的Firebase引用(没有setPersistenceEnabled(true))也没问题。
答案 6 :(得分:1)
我也遇到了一些问题,但这是我的应用程序的临时解决方案。
创建BaseActivity扩展AppcompatActivity并覆盖onCreate,将setPersistenceEnabled
放在那里。
public class BaseActivity extends AppCompatActivity {
private static String TAG = "BaseActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
Log.d(TAG,FirebaseDatabase.getInstance().toString());
}catch (Exception e){
Log.w(TAG,"SetPresistenceEnabled:Fail"+FirebaseDatabase.getInstance().toString());
e.printStackTrace();
}
}
}
更改MainActivity以扩展BaseActivity
public class MainActivity extends BaseActivity
编辑: 关注@imakeApps回答
public class BaseActivity extends AppCompatActivity {
private static String TAG = "BaseActivity";
static boolean isInitialized = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try{
if(!isInitialized){
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
isInitialized = true;
}else {
Log.d(TAG,"Already Initialized");
}
}catch (Exception e){
e.printStackTrace();
}
}
}
答案 7 :(得分:1)
如果你不喜欢静态字段,这对我有用:
if (FirebaseApp.getApps(context).isEmpty()) {
FirebaseApp.initializeApp(context);
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
这可能是因为一个进程初始化两次firebase或Multidex应用程序。有关详细信息,请参阅:https://github.com/firebase/quickstart-android/issues/15
答案 8 :(得分:1)
创建一个名为Util.java的类
并添加以下代码
public class Util {
private static FirebaseDatabase mData;
public static FirebaseDatabase getDatabase() {
if (mData == null) {
mData = FirebaseDatabase.getInstance();
mData.setPersistenceEnabled(true);
}
return mData;
}
}
现在每次在每个活动中用Util.getDatabase()替换FirebaseDatabase.getIntance()。只调用一次就会出错!
答案 9 :(得分:1)
我不建议使用Application来存储数据,因为它类似于用CodePath编写的
应用中的许多地方始终需要数据和信息。这可能是会话令牌,是昂贵计算的结果等。使用应用程序实例可能很有诱惑力,以避免在活动之间传递对象或将其保留在持久存储中的开销。
但是,您永远不应该在Application对象中存储可变实例数据,因为如果您认为您的数据将保留在那里,那么您的应用程序将在某些时候因NullPointerException而不可避免地崩溃。应用程序对象不能保证永远留在内存中,它会被杀死。与流行的看法相反,该应用程序将不会从头开始重新启动。 Android将创建一个新的Application对象并启动用户之前的活动,以便首先假定该应用程序从未被杀死。
这就是我建议使用像这样的Singleton的原因:
public class DataBaseUtil {
private static FirebaseDatabase mDatabase;
public static FirebaseDatabase getDatabase() {
if (mDatabase == null) {
mDatabase = FirebaseDatabase.getInstance();
mDatabase.setPersistenceEnabled(true);
}
return mDatabase;
}}
只需在代码中使用它,就像
一样private FirebaseDatabase fdb = DataBaseUtil.getDatabase();
答案 10 :(得分:0)
只需将ExampleFragment.class中的代码从onCreateView方法移动到onCreate方法:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
....
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_home, container, false);
答案 11 :(得分:0)
对于Kotlin试试这个:
class DatabaseUtil {
companion object {
private val firebaseDatabase: FirebaseDatabase = FirebaseDatabase.getInstance()
init {
firebaseDatabase.setPersistenceEnabled(true)
}
fun getDatabase() : FirebaseDatabase {
return firebaseDatabase
}
}
}
答案 12 :(得分:0)
确保.setpersistenceenabled(true)没有发生两次,而在您的情况下由Google登录,必须先调用第二次护理setPersistenceEnabled(true),然后才能解决我的问题。
答案 13 :(得分:0)
在Menifest中
android:name=".AppName
创建扩展应用程序的java类
public class AppName extends Application {
@Override
public void onCreate() {
super.onCreate();
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
答案 14 :(得分:0)
我遇到了同样的问题。我改变了代码如下。
之前(导致崩溃)
var rootRef = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
FIRDatabase.database().persistenceEnabled = true
}
AFTER(已解决崩溃)
var rootRef:FIRDatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
FIRDatabase.database().persistenceEnabled = true
rootRef = FIRDatabase.database().reference()
}
答案 15 :(得分:-1)
错误消息描述了问题:
必须在任何其他用法之前调用setPersistenceEnabled() FirebaseDatabase实例。
文档中描述了对此问题的修复:与SDK 2.x一样,必须在对数据库进行其他调用之前启用磁盘的持久性。
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
答案 16 :(得分:-2)
您可以使用:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
在使用FirebaseDatabase.getInstance().getReference();