【发布时间】:2016-10-31 12:31:51
【问题描述】:
我正在尝试重构我的 android 应用程序以获得更整洁和易于理解的代码。我正在使用 Firebase 数据库进行数据持久化。
我所做的主要是将我的类重构为单例,因此我可以轻松地在任何其他类中使用它们。
这种方法适用于大多数类(Firebase 存储控制器、GeoFire 控制器、ecc),但我在我的 Auth 控制器上执行此操作时遇到了麻烦,因为它也需要从 Auth 系统和 Db 中检索用户。
下面是我的代码的一些 sn-ps。
开始活动
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 检索用户,所以看起来很难保持同步。
一些尝试
我尝试使用新线程和暂停主线程直到子线程完成的 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;
}
异步任务
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 代表什么?你为什么需要它们?
-
ResultListener 它只是一个接口。我已经更新了显示它的问题。任务完成后,它需要传回结果值(其中包含用户的实例化单例)。我需要这个来将当前用户对象返回到主线程。正如问题中所说:“它需要从 Auth 系统和 Db 中检索用户”
-
真正的问题是如何将 initAuth 方法包装在一个新的线程/异步任务中,以使 firebase 侦听器不在主(睡眠)线程上执行。如我所见,从新线程调用它不是解决方案。我错过了什么吗?
标签: android multithreading firebase firebase-realtime-database firebase-authentication