私はもっときちんとした理解できるコードを得るために私のアンドロイドアプリをリファクタリングしようとしています。私はFirebaseデータベースをデータ永続性のために使用しています。Firebaseデータベースのデータを同期的にロードするにはどうすればいいですか?
私がやったことは、ほとんどが自分のクラスをシングルトンにリファクタリングすることなので、他のクラスでも簡単に使うことができます。
このアプローチは、ほとんどのクラス(Firebase Storage Controller、GeoFire Controller、ecc)で機能しましたが、AuthシステムとDbからユーザを取得する必要があるため、Authコントローラでこれを行うのに問題があります。 。
以下、私のコードの抜粋です。
開始アクティビティ
public class StartActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
AuthController.getInstance(new ResultListener<AuthController>(){
@Override
public void onResult(AuthController result) {
AuthController authController = result;
Intent intent;
if (authController.getUser() != null) {
intent = new Intent(getApplicationContext(), MainActivity.class);
} else {
intent = new Intent(getApplicationContext(), LoginActivity.class);
}
startActivity(intent);
finish();
}
});
}
}
マイ認証コントローラ
public class AuthController {
private static AuthController authController;
private User user;
public User getUser() {
return user;
}
public static AuthController getInstance(){
if(authController == null){
getInstance(null);
//TODO return authController
}
return authController;
}
public static void getInstance(final ResultListener<AuthController> authControllerResultListener) {
initAuth(new ResultListener<AuthListener>() {
@Override
public void OnResult(AuthController authController) {
AuthController.authController = authController;
if(authControllerResultListener != null) {
authControllerResultListener.onResult(authController);
}
}
});
}
private static void initAuth(final ResultListener<AuthController> authListener) {
final AuthController authController = new AuthController();
FirebaseAuth mAuth = FirebaseAuth.getInstance();
mAuth.addAuthStateListener(new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
final FirebaseUser authUser = firebaseAuth.getCurrentUser();
if (authUser != null) {
String authUserId = authUser.getUid();
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
firebaseDatabase.getReference("users").child(authUserId).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
authController.user = dataSnapshot.getValue(User.class);
authListener.onResult(authController);
}
@Override
public void onCancelled(DatabaseError databaseError) {
authController.user = null;
authListener.onResult(authController);
}
});
} else {
authController.user = null;
authListener.onResult(authController);
}
}
});
}
}
マイ抽象活動、これは認証コントローラのインスタンスを使用する必要が私の他の活動によって拡張されます。
public abstract class MyAppActivity extends AppCompatActivity {
protected final AuthController authController = AuthController.getInstance();
}
結果リスナーインタフェース
public interface ResultListener<ResultType> {
void onResult(ResultType result);
}
だから私は何をしたいの同期方法では、もちろんのユーザーが含まれている私の認証コントローラのインスタンスを取得することで、ユーザーはfirebaseから検索する必要があるため、同期を維持することは難しいようです。
子スレッドが終了するまで、メインスレッドを一時停止するいくつかの試み
私は新しいスレッドを使用してみましたし、参加してきましたが()、しかしFirebaseリスナーがメインスレッド上で実行することが表示されますので、コードは実行中にスタックしてしまいます。 AsyncTask(下記参照)と同じです。
新しいスレッド
public static AuthController getInstance(){
if(authController == null){
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
initAuth(new ResultListener<AuthController>() {
@Override
public void onResult(AuthController authController) {
AuthController.authController = authController;
}
});
}
});
thread.run();
thread.join();
}
return authController;
}
AsyncTask
public static AuthController getInstance(){
if(authController == null){
final Semaphore semaphore = new Semaphore(0);
InitAuthAsync initAuthAsync = new AuthController().new InitAuthAsync();
initAuthAsync.setResultListener(new ResultListener<Void>() {
@Override
public void onResult(Void result) {
semaphore.release();
}
});
initAuthAsync.execute();
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return authController;
}
private class InitAuthAsync extends AsyncTask<Void, Void, Void>{
private ResultListener<Void> resultListener;
public void setResultListener(ResultListener<Void> resultListener) {
this.resultListener = resultListener;
}
@Override
protected Void doInBackground(Void... voids) {
initAuth(new ResultListener<AuthController>() {
@Override
public void onResult(AuthController authController) {
AuthController.authController = authController;
resultListener.onResult(aVoid);
}
});
return null;
}
}
任意の提案?
FriebaseAuthはすでにシングルトンです。皮肉なことに、スパゲッティのコードを使って、もっときれいにするようです。 AuthListener、ResultListenerの略語は何ですか?なぜあなたはそれらを必要としますか? – uguboz
ResultListenerそれは単なるインタフェースです。私はそれを示す質問を更新しました。タスクが完了すると、結果値(ユーザが内部でインスタンス化されたシングルトン)を返す必要があります。現在のユーザーオブジェクトをメインスレッドに戻すには、これが必要です。 質問:「AuthシステムとDbからユーザを取得する必要があります」 –
実際の問題は、firebaseリスナーが新しいスレッド/非同期タスクにinitAuthメソッドをラップする方法ですメイン(スリープ)スレッドでは実行されません。私が見ることができるように、それを新しいスレッドから呼び出すことは解決策ではありません。何か不足していますか? –