我有一个表单,需要电子邮件和密码。所以在输入数据后,我先检查电子邮件是否已在文档中可用(在Firebase Firestore数据库中)。如果不可用,我将插入这些数据。但我的代码总是先插入,然后再执行检查已经存在的内容。有没有任何方法可以解决它,而不使用我的插入代码内的检查代码。
For example, my database already has "test@gmail.com" document. When I input the same email and submit then it will show Account available. Can not sign up! But my code inserts again then check for the email availability in DB.
感谢您抽出宝贵的时间。
XML代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:paddingTop="30dp">
<View
android:layout_width="400dp"
android:layout_height="1dp"
android:background="#678049"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:layout_marginBottom="30dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginTop="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email"
android:textSize="20dp"
android:textColor="@color/black"
android:layout_marginLeft="5dp"
android:layout_gravity="center|top"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginTop="5dp">
<EditText
android:id="@+id/UserEmail"
android:layout_width="345dp"
android:layout_height="40dp"
android:textSize="20dp"
android:background="#5676"
android:hint="Enter Email Adress.."
android:inputType="text"
android:layout_marginLeft="3dp"/>
</LinearLayout>
<Space
android:layout_width="match_parent"
android:layout_height="5dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginTop="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Password"
android:textColor="@color/black"
android:textSize="20dp"
android:layout_marginLeft="5dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginTop="5dp">
<EditText
android:id="@+id/UserPassword"
android:layout_width="345dp"
android:layout_height="40dp"
android:textSize="20dp"
android:background="#5676"
android:hint="Enter Password.."
android:layout_marginVertical="13dp"
android:inputType="textPassword" />
</LinearLayout>
<Button
android:id="@+id/btnSubmit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:padding="10dp"
android:layout_marginHorizontal="80dp"
android:backgroundTint="#4C4B4B"
android:text="Sign up"
android:textColor="#F5FBF6" />
</LinearLayout>
Java代码
public class MainActivity extends AppCompatActivity {
public static final String COLLECTION_USER = "collection_user";
EditText userEmail, userPassword;
Button btnSignUp;
boolean accountAlreadyAvailable = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userEmail = findViewById(R.id.UserEmail);
userPassword = findViewById(R.id.UserPassword);
btnSignUp = findViewById(R.id.btnSubmit);
btnSignUp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String email = userEmail.getText().toString();
String password = userPassword.getText().toString();
Map<String, Object> data = new HashMap<>();
data.put("email", email);
data.put("password", password);
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection(COLLECTION_USER).document(email)
.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if(task.getResult().exists()) {
accountAlreadyAvailable = true;
Log.d(TAG, "Account available changed to: " + accountAlreadyAvailable);
}
}
});
//As no email document found,
//new data will insert to firebase firestore database
Log.d(TAG, "Account available: " + accountAlreadyAvailable);
if(accountAlreadyAvailable == false) {
db.collection(COLLECTION_USER).document(email).set(data).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if(task.isSuccessful()) {
Log.d(TAG, "Data inserted as no account found");
}
}
});
} else {
Log.d(TAG, "Account available. Can not sign up!");
}
}
});
}
}
2条答案
按热度按时间fdbelqdn1#
数据是从Firestore(以及大多数现代云API)异步加载的,这会改变代码执行的顺序,而不是您可能习惯的顺序。通过设置断点并在调试器中运行,或者添加一些日志记录,最容易看到这一点:
当您运行此代码时,它会记录:
调用get()之前
调用get()后
获取数据
这可能不是您预期的代码执行顺序,但它按设计工作,并完美地解释了为什么第二次读取数据库时不起作用:到运行
accountAlreadyAvailable = true
的时候还没有执行。此类问题的解决方案始终相同:需要来自数据库的数据的任何代码必须在X1 M1 N1 X内部,从那里被调用,或者以其他方式被同步。
最简单的修复方法是将第二个读取操作移到第一个的
onComplete
中:现在,第二次读取仅在第一次读取完成且
accountAlreadyAvailable
已设置后执行。处理异步API调用是一个非常常见的问题,因此我建议您仔细阅读它。
sqougxex2#
这些调用是异步的,所以你放入
onComplete
中的代码不会按顺序运行--它会在将来某个时候运行,当数据可用时,你必须相应地构造你的代码。你不能只写一个长函数,然后期望它像使用同步方法一样工作。有很多方法可以解决这个问题,但是所有的方法都要求你理解回调代码(无论是你自己的自定义回调还是传递给Firestore的回调)不会立即运行。自定义回调很少有必要作为一个解决方案- Firestore * 已经 * 使用了回调。相反,你只需要理解回调是如何工作的,并正确地使用它。
例如,您可以通过将工作分解为几个功能来解决问题:
其中调用的第一个函数发出第一个异步请求
然后调用
onComplete
内部的下一个函数,直到数据被获取,你不能调用这个函数,并且直到你的监听器被调用。