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();
}
}
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.
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"
... />
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!
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é
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);
}
}
}
}
}
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
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.
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!
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();
}
}
}
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();
Pour Kotlin Essayez ceci:
class DatabaseUtil {
companion object {
private val firebaseDatabase: FirebaseDatabase = FirebaseDatabase.getInstance()
init {
firebaseDatabase.setPersistenceEnabled(true)
}
fun getDatabase() : FirebaseDatabase {
return firebaseDatabase
}
}
}
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);
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);
}
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.
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()
}