【发布时间】:2020-07-13 06:50:52
【问题描述】:
我正在开发一个执行以下操作的 Android 应用:
- 在应用启动时,它会使用 AuthStateListener 检查用户是否已登录。
- 如果有用户登录,它会从 Firestore 中检索数据。用户数据存储在我使用以下命名法命名的文档中:“用户”+用户的_email_ID。 例如,如果用户的电子邮件 ID xyz@gmail.com,他的数据将存储在名为:User xyz@gmail.com。 所有文档都在名为“Users”的集合中。
- 如果用户数据文档中的所有字段均为空/空,应用程序会打开一个 Activity,要求他/她填写所有详细信息。否则,它将用户带到主页(如果用户是学生,则为StudentMainActivity,如果用户是教授,则为ProfessorMainActivity)。
来解决我的问题:
检查字段是否为空的代码块有一些不稳定和不可预测的行为。我不确定这是基于 Firestore 的问题,还是数据检索发生在不同线程上的问题。
我检查了 Firestore 数据库,发现所有字段都已填写。但是,当用户(已经登录)启动应用程序时,应用程序知道它是同一个用户(即他没有被提示登录,因为 AuthStateListener 完成了它的工作),而不是被重定向到 StudentMainActivity 或 ProfessorMainActivity (主屏幕),他被要求再次填写他的详细信息。
更令人困惑的是,这个错误并不总是发生。有时应用会执行预期的操作,即将用户带到主屏幕,但下次启动应用时,他会再次被带到要求他输入详细信息的活动。
源代码:
LoginActivity.java(仅相关部分)
//AuthStateListener is in onCreate
authStateListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null){
UIDEmailID = user.getEmail();
updateUI(user);
}
else{
updateUI(null);
}
}
};
private void updateUI(FirebaseUser user){
// Update UI after login
if (user != null) {
Toast.makeText(LoginActivity.this, "User " + UIDEmailID, Toast.LENGTH_LONG).show();
db.collection("Users").document("User " + UIDEmailID).get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
@Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.get("department") != null || // if any
documentSnapshot.get("phoneNumber") != null || // field in
documentSnapshot.get("name") != null || // Firestore is
documentSnapshot.get("studentSemester") != null || // non-null then
documentSnapshot.get("dateOfBirth") != null || // proceed to
documentSnapshot.get("university") != null) { // further activities
if (documentSnapshot.get("userType") == "Lecturer/ Professor") {
Intent intent = new Intent(LoginActivity.this, ProfessorMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
else {
Intent intent = new Intent(LoginActivity.this, StudentMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
} else {
Toast.makeText(LoginActivity.this, "We need some additional details before we go ahead.", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(LoginActivity.this, GFBDetailsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(LoginActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
很抱歉这个问题太长了;我只是试图使它具有超级描述性。一些帮助将不胜感激。
P.S. 我认为这是一个涉及使用多线程的问题的原因是,每当应用程序按预期运行(即,将用户带到主屏幕)时,“我们需要一些在我们继续之前提供更多详细信息。”也出现。如果您查看代码(最后一个“else”块),您会意识到它完全位于单独的条件块中,因此如果主屏幕(位于另一个条件块中)显示,甚至不应该显示起来。
编辑 1:
我附上了与问题相关的屏幕截图。忽略平淡的用户界面:P
这是预期的(位于第二个“else”块下)。它应该仅在用户第一次登录时显示,即没有将他的数据存储在 Firestore 文档中。
背景是 StudentMainActivity(在嵌套的“else”内)。但是,即使是 Toast 也会显示(它完全属于一个单独的块)。
【问题讨论】:
-
你能到达 onSucess() 方法的第一个 if 吗?还是直接跳转到else?请在变量用户的 if 之前打印并分享变量用户有什么?
-
查看您的代码,我发现可能是代码错误,要获取您当前的用户数据,您必须使用以下代码: FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();如果您仍然遇到相同的问题,请您输入以前的代码并重试吗?请让我知道它是否有效。
-
我已经分析了你的代码,它似乎是正确的,为了进一步的故障排除,你能否在 onSucess 方法中的第一个 if 之前请 System.out.prinln(documentSnapshot) 查看来自 firestore 的数据是否是被正确检索?能否请您分享您的 manifest.xml 文件,也请您分享您的 Student、Professor 和 GFBDetailsActivity 的文件(代码)?活动打开错误似乎有问题。
-
感谢分享您的代码,我一直在查看您的代码。我想我能够找到问题所在。也许您查询错误,这就是 documentSnapshot 为空且没有显示的原因。您能否告诉我您的 Firestore 的结构,我的意思是在这里我想看看您的文档 ID 是如何命名的?查询是空的,因为可能 UIDEmailID 是空的,请敬酒或在 onAuthStateChanged 中打印 UIDEmailID 并查看它是什么?
-
你也可以这样查询一个文档: db.collection(COLLECTION_NAME) .whereEqualTo(DOCUMENT_ID, documentId) .get() .addOnCompleteListener(task -> { if (task.isSuccessful()) { if (task.getResult().getDocuments().size() > 0) // 这是你的文档,id } });
标签: java android firebase google-cloud-firestore firebase-authentication