setPersistenceEnabled(true)崩溃应用程序

时间:2016-05-25 21:46:48

标签: firebase firebase-realtime-database firebase-authentication

我正在创建我的第一个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();
        }
    } 

17 个答案:

答案 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()

Read more in this article

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

https://firebase.google.com/support/guides/firebase-android

答案 16 :(得分:-2)

您可以使用:

FirebaseDatabase.getInstance().setPersistenceEnabled(true);

在使用FirebaseDatabase.getInstance().getReference();

之前