最初の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();
}
}
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()
を呼び出します。
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"
... />
私は同様の問題に直面していましたが、静的変数を使用することで問題が解決したようです。だから、最初は私のコードは次のように見えました
@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
}
それが役に立てば幸い!
少し遅れましたが、今日この問題が発生しました。
static {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
私の活動へ
私にとっては、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);
}
}
}
}
}
静的フィールドが気に入らない場合は、これでうまくいきました。
if (FirebaseApp.getApps(context).isEmpty()) {
FirebaseApp.initializeApp(context);
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
これは、FirebaseまたはMultidexアプリを2回初期化する1つ以上のプロセスで発生する可能性があります。詳細については、これを参照してください: https://github.com/firebase/quickstart-Android/issues/15
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)なし)を作成しても問題ありません。
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()に置き換えてください各アクティビティごとに一度だけ呼び出すとエラーが発生します!
私もいくつかの問題に直面していますが、これは私のアプリの一時的な解決策です。
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();
}
}
}
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();
Kotlinの場合:
class DatabaseUtil {
companion object {
private val firebaseDatabase: FirebaseDatabase = FirebaseDatabase.getInstance()
init {
firebaseDatabase.setPersistenceEnabled(true)
}
fun getDatabase() : FirebaseDatabase {
return firebaseDatabase
}
}
}
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);
マニフェスト内
Android:name=".AppName
Create Java Applicationを拡張するクラス
public class AppName extends Application {
@Override
public void onCreate() {
super.onCreate();
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
.setpersistenceenabled(true)が2回発生していないことを確認してください。この場合、Googleによるサインイン中に、セカンドケアsetPersistenceEnabled(true)を呼び出してから、これを呼び出すfirebaseのインスタンスが問題を解決します。
私は同じ問題に直面していました。以下のようにコードを変更しました。
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()
}