web-dev-qa-db-ja.com

setPersistenceEnabled(true)がアプリをクラッシュさせる

最初のFirebaseアプリを作成しています。その要件の1つは、ネットワークが利用できないときに実行することです。 Firebaseガイドの状態:

ディスクの永続性を有効にすると、アプリを再起動した後でも、アプリはその状態をすべて維持できます。 1行のコードでディスクの永続化を有効にできます。 FirebaseDatabase.getInstance()。setPersistenceEnabled(true);ディスク永続性を有効にすると、同期データと書き込みはアプリの再起動後もディスクに永続化され、アプリはオフラインの状況でもシームレスに動作するはずです。

別の要件は、Googleサインインを使用することです。したがって、私のMainActivityでユーザーがサインインしているかどうかを確認し、サインインしていない場合は、SignInActivityを起動します。 (SignInActivityはFirebaseの例です。)SignInActivityは機能し、ユーザーはログインし、MainActivityが2回目に起動します。これで、コード行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();
        }
    } 
35
Loren

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()を呼び出します。

この記事の詳細を読む

51
Dan Alboteanu

ApplicationクラスでsetPersistenceEnabled(true)を使用して、この例外を修正しました。

public class MApplication extends Application {

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

AndroidManifest.xmlで、アプリケーション名をMApplicationに設定します。

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

私は同様の問題に直面していましたが、静的変数を使用することで問題が解決したようです。だから、最初は私のコードは次のように見えました

@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
}

それが役に立てば幸い!

25
imakeApps

少し遅れましたが、今日この問題が発生しました。

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

私の活動へ

17
rkmax

私にとっては、Firebase用に別のクラスを作成することで、簡単に処理できます。これは、Firebaseには独自のインスタンスがあり、複数のアクティビティで使用している場合、別のアクティビティでsetPersistenceEnabledを再度呼び出すとクラッシュする可能性があるためです。

もう1つの良い点は、必要に応じてコンテキストまたはパラメーターを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);
                }
            }
        }
    }
}
3
tingyik90

静的フィールドが気に入らない場合は、これでうまくいきました。

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

これは、FirebaseまたはMultidexアプリを2回初期化する1つ以上のプロセスで発生する可能性があります。詳細については、これを参照してください: https://github.com/firebase/quickstart-Android/issues/15

1
Yair Kukielka

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)なし)を作成しても問題ありません。

1
Helmwag

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()に置き換えてください各アクティビティごとに一度だけ呼び出すとエラーが発生します!

1
Rijvi Zaman

私もいくつかの問題に直面していますが、これは私のアプリの一時的な解決策です。

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

CodePathで記述されているように、アプリケーションを使用してデータを保存することはお勧めしません

アプリ内の多くの場所で必要なデータと情報が常にあります。これはセッショントークン、高価な計算の結果などである可能性があります。アクティビティ間でオブジェクトを渡したり、永続ストレージにオブジェクトを保持したりするオーバーヘッドを回避するために、アプリケーションインスタンスを使用したくなるかもしれません。

ただし、アプリケーションオブジェクト内に可変インスタンスデータを格納しないでください。データがそこにとどまると仮定すると、アプリケーションは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();
1
Musab Kurt

Kotlinの場合:

class DatabaseUtil {

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

        init {
            firebaseDatabase.setPersistenceEnabled(true)
        }

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

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);
0
Zamatto Koizumi

マニフェスト内

 Android:name=".AppName

Create Java Applicationを拡張するクラス

public class AppName extends Application {

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

}
0
Pankaj Kudawala

.setpersistenceenabled(true)が2回発生していないことを確認してください。この場合、Googleによるサインイン中に、セカンドケアsetPersistenceEnabled(true)を呼び出してから、これを呼び出すfirebaseのインスタンスが問題を解決します。

0
Sachin Keche

私は同じ問題に直面していました。以下のようにコードを変更しました。

BEFORE(クラッシュの原因)

    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()
}
0