如何以同步方式加载Firebase数据库数据?

时间:2016-10-31 12:31:52

标签: android multithreading firebase firebase-realtime-database firebase-authentication

我正在尝试重构我的Android应用程序以获得更整洁和易懂的代码。我正在使用Firebase数据库来保持数据持久性。

我所做的,主要是将我的课程重构为单身,所以我可以轻松地在任何其他课程中使用它们。

这种方法适用于大多数类(Firebase存储控制器,GeoFire控制器,ecc),但我在Auth控制器上执行此操作时遇到了麻烦,因为它需要从Auth系统和Db中检索用户。

下面是我的代码的一些片段。

开始活动

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

}

我的抽象活动,这是由我需要使用auth控制器实例的其他活动扩展的。

public abstract class MyAppActivity extends AppCompatActivity {

    protected final AuthController authController = AuthController.getInstance();

}

结果侦听器界面

public interface ResultListener<ResultType> {
    void onResult(ResultType result);
}

所以我想做的是获取一个以同步方式包含用户的auth控制器实例,但当然,必须从firebase中检索用户,所以看起来好像难以保持同步。

有些尝试

我尝试使用新的Thread和join()暂停主线程直到子线程完成,但看起来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;
    }

}

有什么建议吗?

2 个答案:

答案 0 :(得分:0)

你的代码很乱。简单的观察者模式将适用于您的情况。我建议你使用轻量级且易于使用的Eventbus Library

答案 1 :(得分:0)

如果有人需要,我发现了一个解决方案。请注意,这不是与firebase一起使用的最佳架构。

time