Подтвердить что ты не робот

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();
        }
    } 
4b9b3361

Ответ 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();