SetPersistenceEnabled (true) аварийное приложение
Я создаю свое первое приложение Firebase. Одним из его требований является то, что он работает, когда сеть недоступна. Руководство Firebase гласит:
Включение сохранения диска позволяет нашему приложению также сохранять все его состояние даже после перезапуска приложения. Мы можем включить сохранение диска только одной строкой кода. FirebaseDatabase.getInstance() setPersistenceEnabled (истина). С включенным постоянством диска наши синхронизированные данные и записи будут сохраняться на диск при перезапуске приложения, и наше приложение должно бесперебойно работать в автономном режиме.
Еще одно требование - использовать Google Sign In. Поэтому в своей MainActivity
я проверяю, MainActivity
ли пользователь, если нет, я запускаю SignInActivity
. (SignInActivity
из примеров Firebase.) SignInActivity
работает, пользователь SignInActivity
в систему, и MainActivity
запускается во второй раз. Теперь мое приложение вылетает в строке кода FirebaseDatabase.getInstance().setPersistenceEnabled(true);
со следующим сообщением:
Вызовы setPersistenceEnabled() должны быть сделаны перед любым другим использованием экземпляра FirebaseDatabase.
Теперь, если я перезапущу свое приложение, пользователь SignInActivity
в систему, 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();
}
}
Ответы
Ответ 1
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()
из любого действия, которое вы хотите.
Узнайте больше в этой статье
Ответ 2
Я исправил это исключение, используя 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"
... />
Ответ 3
Я столкнулся с аналогичной проблемой, и использование статической переменной, казалось, разрешило проблему для меня. Итак, сначала мой код выглядел примерно так.
@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
}
Надеюсь, что это поможет!
Ответ 4
Я немного опоздал, но сегодня я получил эту проблему, я решил, добавив
static {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
для моей деятельности
Ответ 5
Для меня легче обрабатывать, создавая отдельный класс для Firebase. Это связано с тем, что Firebase имеет свой собственный экземпляр, и если вы используете его более чем в одном действии, есть возможность его сбой, если вы снова вызовеете setPersistenceEnabled в другом действии.
Другое дело, что вы можете передать свой контекст или параметры в конструктор FirebaseHandler, если это необходимо. Или, если у вас есть фиксированное местоположение в базе данных, их можно легко назвать без шаблона .child( "location" ).
Пример:
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);
}
}
}
}
}
Ответ 6
У меня тоже есть проблема, но это мое временное решение для моего приложения.
Создать 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
EDIT: Следуйте за ответом @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
Решив его, сделав ссылку 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)) в других действиях.
Ответ 8
Если вам не нравятся статические поля, это помогло мне:
if (FirebaseApp.getApps(context).isEmpty()) {
FirebaseApp.initializeApp(context);
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Это может быть вызвано тем, что один процесс инициализирует дважды Firebase или Multidex приложения. Для получения дополнительной информации см. Это: https://github.com/firebase/quickstart-android/issues/15
Ответ 9
Я бы не рекомендовал использовать приложение для хранения данных, так как он написан в CodePath
Всегда есть данные и информация, которые необходимы во многих местах вашего приложения. Это может быть токен сеанса, результат дорогостоящего вычисления и т.д. Возможно, возникает соблазн использовать экземпляр приложения, чтобы избежать накладных расходов на передачу объектов между действиями или сохранение их в постоянном хранилище.
Однако вы никогда не должны хранить изменяемые данные экземпляра внутри объекта Application, потому что, если вы предполагаете, что ваши данные останутся там, ваше приложение неизбежно будет сбой в какой-то момент с помощью исключения NullPointerException. Объект приложения не гарантированно останется в памяти навсегда, он будет убит. Вопреки распространенному мнению, приложение не будет перезапущено с нуля. Android создаст новый объект приложения и начнет действие, в котором пользователь был раньше, чтобы представить иллюзию, что приложение никогда не было убито в первую очередь.
Вот почему я рекомендую использовать синглтон следующим образом:
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
Создайте класс под названием Util.java
и добавьте следующий код
public class Util {
private static FirebaseDatabase mData;
public static FirebaseDatabase getDatabase() {
if (mData == null) {
mData = FirebaseDatabase.getInstance();
mData.setPersistenceEnabled(true);
}
return mData;
}
}
Теперь замените FirebaseDatabase.getIntance() на Util.getDatabase() каждый раз в каждом действии. Вызов только один раз получит ошибку!
Ответ 11
Я столкнулся с такой же проблемой. Я изменил код, как показано ниже.
ПЕРЕД (Причиной сбоя)
var rootRef = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
FIRDatabase.database().persistenceEnabled = true
}
ПОСЛЕ (разрешенный сбой)
var rootRef:FIRDatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
FIRDatabase.database().persistenceEnabled = true
rootRef = FIRDatabase.database().reference()
}
Ответ 12
В Menifest
android:name=".AppName
Создать класс Java, расширяющий приложение
public class AppName extends Application {
@Override
public void onCreate() {
super.onCreate();
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Ответ 13
Удостоверьтесь, что .setpersistenceenabled(true) не происходит дважды, в то время как вы регистрируетесь в Google в своем случае, вторая помощь setPersistenceEnabled (true) должна быть вызвана до того, как любой экземпляр firebase назвал это решением моей проблемы.
Ответ 14
Для Kotlin Попробуйте это:
class DatabaseUtil {
companion object {
private val firebaseDatabase: FirebaseDatabase = FirebaseDatabase.getInstance()
init {
firebaseDatabase.setPersistenceEnabled(true)
}
fun getDatabase() : FirebaseDatabase {
return firebaseDatabase
}
}
}
Ответ 15
Просто переместите свой код в 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);
Ответ 16
Сообщение об ошибке описывает проблему:
Вызовы setPersistenceEnabled() должны быть сделаны до любого другого использования экземпляра FirebaseDatabase.
Исправление этой проблемы описано в документации: Как и в SDK 2.x, персистентность диска должна быть включена до того, как будут сделаны другие вызовы в базе данных.
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
https://firebase.google.com/support/guides/firebase-android
Ответ 17
Вы можете использовать:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
перед использованием FirebaseDatabase.getInstance().getReference();