web-dev-qa-db-fra.com

setPersistenceEnabled (true) bloque l'application

Je crée ma première application Firebase. L'une de ses exigences est qu'il s'exécute lorsque le réseau n'est pas disponible. Le guide Firebase indique: 

L'activation de la persistance du disque permet à notre application de conserver également tout son état, même après le redémarrage de l'application. Nous pouvons activer la persistance du disque avec une seule ligne de code . FirebaseDatabase.getInstance (). SetPersistenceEnabled (true); Avec la persistance du disque activée, nos données synchronisées et nos écritures seront conservées sur le disque lors du redémarrage des applications et notre application devrait fonctionner de manière transparente dans des situations hors ligne.

Vous devez également utiliser Google Sign In. Donc, dans ma MainActivity je vérifie si l'utilisateur est connecté, sinon je lance la SignInActivity. (La SignInActivity provient des exemples de Firebase.) La SignInActivity fonctionne, l'utilisateur est connecté et MainActivity est lancé une seconde fois. Maintenant, mon application se bloque sur la ligne de code FirebaseDatabase.getInstance().setPersistenceEnabled(true); avec le message suivant: 

Les appels à setPersistenceEnabled () doivent être effectués avant toute autre utilisation de l'instance FirebaseDatabase.

Maintenant, si je redémarre mon application, l'utilisateur est connecté, la SignInActivity n'est pas lancée, mon application fonctionne correctement.

Avez-vous des suggestions sur la manière d’éviter ce blocage après la connexion de l’utilisateur?

Alors que je postais cette question, on m'a suggéré de déplacer FirebaseDatabase.getInstance().setPersistenceEnabled(true);dans ma "classe d'application". Je reçois exactement le même résultat… SignInActivity commence, se termine et je reçois un crash sur la setPersistenceEnabled.

Ci-dessous ma 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();
        }
    } 
35
Loren

Une FirebaseApp est initialisée par une ContentProvider, de sorte qu'elle n'est pas initialisée au moment où onCreate() est appelé.

Obtenez votre base de données FirebaseDate comme ceci:

public class Utils {
    private static FirebaseDatabase mDatabase;

    public static FirebaseDatabase getDatabase() {
       if (mDatabase == null) {
          mDatabase = FirebaseDatabase.getInstance();
          mDatabase.setPersistenceEnabled(true);
       }
       return mDatabase;
    }

}

Ensuite, appelez Utils.getDatabase() à partir de l’activité de votre choix.

Lire la suite dans cet article

49
Dan Alboteanu

J'ai corrigé cette exception en utilisant setPersistenceEnabled(true) dans ma classe Application.

public class MApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        FirebaseDatabase.getInstance().setPersistenceEnabled(true);
    }
}

Dans AndroidManifest.xml, définissez le nom de l'application sur MApplication:

<application
    Android:name=".MApplication"
    ... />
45
dknchris

Je faisais face à un problème similaire et l’utilisation d’une variable statique a semblé résoudre le problème pour moi. Donc au début, mon code ressemblait à quelque chose comme ça 

@Override
protected void onCreate(Bundle savedInstanceState) {
    //..code

    FirebaseDatabase.getInstance().setPersistenceEnabled(true);
    FirebaseDatabase database = FirebaseDatabase.getInstance();

    //..code
}

et maintenant ça ressemble plus à

static boolean calledAlready = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    //..code

    if (!calledAlready)
    {
        FirebaseDatabase.getInstance().setPersistenceEnabled(true);
        calledAlready = true;
    }

    FirebaseDatabase database = FirebaseDatabase.getInstance();

    //..code
}

J'espère que ça aide!

24
imakeApps

J'ai un peu tard mais aujourd'hui j'ai ce problème, j'ai résolu en ajoutant

static {
    FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}

à mon activité

14
rkmax

Pour moi, il est plus facile d’être traité en créant une classe distincte pour Firebase. En effet, Firebase a sa propre instance et si vous l’utilisez dans plusieurs activités, il est possible que celle-ci se bloque si vous appelez setPersistenceEnabled dans une autre activité.

Une autre bonne chose est que vous pouvez passer votre contexte ou vos paramètres dans le constructeur FirebaseHandler si nécessaire. Ou si vous avez un emplacement fixe dans la base de données, vous pouvez l'appeler facile sans le passe-passe .child ("emplacement").

Exemple:

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);
    }
}

Ceci peut ensuite être appelé dans n'importe quelle activité comme ci-dessous.

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);
                }
            }
        }
    }
}
3
tingyik90

Si vous n'aimez pas les champs statiques, voici ce que j'ai fait:

if (FirebaseApp.getApps(context).isEmpty()) {
     FirebaseApp.initializeApp(context);
     FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}

Cela peut être causé par plus d'un processus qui initialise deux applications firebase ou Multidex. Pour plus d'informations, voir ceci: https://github.com/firebase/quickstart-Android/issues/15

1
Yair Kukielka

Résolu en faisant en sorte que la base de données Firebase fasse référence à un champ de classe statique comme ceci:

public class MainActivity extends AppCompatActivity

private static FirebaseDatabase fbDatabase;

@Override
    protected void onCreate(Bundle savedInstanceState) {

if(fbDatabase == null) {
            fbDatabase = FirebaseDatabase.getInstance();
            fbDatabase.setPersistenceEnabled(true);
        }

Ce n'est pas un problème de créer de nouvelles références Firebase (sans setPersistenceEnabled (true)) dans d'autres activités également.

1
Helmwag

Créez une classe appelée Util.Java

et ajouter le code suivant

public class Util {

        private static FirebaseDatabase mData;

        public static FirebaseDatabase getDatabase() {
            if (mData == null) {

                mData = FirebaseDatabase.getInstance();
                mData.setPersistenceEnabled(true);
            }
            return mData;
        }


}

Maintenant, remplacez FirebaseDatabase.getIntance () par Util.getDatabase () à chaque fois dans chaque activité. Appeler une seule fois aura l'erreur!

1
Rijvi Zaman

Je suis également confronté à un problème, mais il s'agit de ma solution temporaire pour mon application. 

Create BaseActivity étend AppcompatActivity et remplace onCreate en y mettant 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();
        }
    }
}

Et changez MainActivity pour étendre BaseActivity

public class MainActivity extends BaseActivity

EDIT: Suivez @imakeApps répondre

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();
        }
    }
}
1
Sucipto

Je ne recommanderais pas d'utiliser Application pour stocker les données car, comme dans ScriptPath 

Il existe toujours des données et des informations nécessaires dans de nombreux endroits de votre application. Il peut s’agir d’un jeton de session, d’un calcul coûteux, etc. Il peut être tentant d’utiliser l’instance d’application afin d’éviter la surcharge liée au transfert d’objets entre activités ou à leur conservation en stockage persistant.

Cependant, vous ne devriez jamais stocker de données d'instance mutables dans l'objet Application, car si vous supposez que vos données y resteront, votre application se bloquera inévitablement à un moment donné avec une exception NullPointerException. L'objet d'application n'est pas garanti pour rester en mémoire pour toujours, il sera tué. Contrairement à la croyance populaire, l’application ne sera pas redémarrée à partir de zéro. Android va créer un nouvel objet Application et démarrer l'activité où l'utilisateur était auparavant pour donner l'illusion que l'application n'a jamais été supprimée.

C'est la raison pour laquelle je recommanderais d'utiliser un Singleton comme ceci:

public class DataBaseUtil {

private static FirebaseDatabase mDatabase;

public static FirebaseDatabase getDatabase() {
    if (mDatabase == null) {
        mDatabase = FirebaseDatabase.getInstance();
        mDatabase.setPersistenceEnabled(true);
    }
    return mDatabase;
}}

juste l'utiliser dans votre code alors comme 

private FirebaseDatabase fdb = DataBaseUtil.getDatabase();
1
Musab Kurt

Pour Kotlin Essayez ceci:

class DatabaseUtil {

    companion object {
        private val firebaseDatabase: FirebaseDatabase = FirebaseDatabase.getInstance()

        init {
            firebaseDatabase.setPersistenceEnabled(true)
        }

        fun getDatabase() : FirebaseDatabase {
            return firebaseDatabase
        }
    }
}
0
Farhan Ar Rafi

Déplacez simplement votre code dans ExampleFragment.class de la méthode onCreateView vers la méthode 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);
0
Zamatto Koizumi

In Manifest

 Android:name=".AppName

Créer une classe Java qui étend l'application

public class AppName extends Application {

@Override
public void onCreate() {
    super.onCreate();
    FirebaseDatabase.getInstance().setPersistenceEnabled(true);

}
0
Pankaj Kudawala

Assurez-vous que .setpersistenceenabled (true) ne se produit pas deux fois. Lors de la connexion par Google dans votre cas, second care setPersistenceEnabled (true) doit être appelé avant toute instance de firebase appelée ainsi résoudre ce problème.

0
Sachin Keche Patil

Je faisais face au même problème. J'ai changé le code comme ci-dessous.

AVANT (Causing Crash)

    var rootRef = FIRDatabase.database().reference()

    override func viewDidLoad() {
       super.viewDidLoad()
       FIRDatabase.database().persistenceEnabled = true
    }

APRÈS (crash résolu)

var rootRef:FIRDatabaseReference!
override func viewDidLoad() {
 super.viewDidLoad()
   FIRDatabase.database().persistenceEnabled = true
   rootRef = FIRDatabase.database().reference()
}
0
Dattatray Deokar