使用 AsyncTask 读取 Firestore 文档
reading Firestore documents with AsyncTask
我在 Cloud Firestore 中有一个数据库,其中每个文档都有一个特定的键 "last update" 和值,一个字符串,表示 YYYY-MM-DD 格式的日期。每次更新文档时,"last update" 的值被设置为更新日期。
现在,我希望我的 activity 有一个方法来检查文档的最后更新。由于文档包含相当大的对象列表,因此此更新检查需要几秒钟。所以我决定将它推迟到 AsyncTask。 AsyncTask 的 doInBackground 方法应该为文档创建一个 DocumentReference,noteRef,并用 noteRef.get() 读取它的 "last update",配备
onSuccess- 和 onFailure 侦听器,转换为一个字符串,然后由该方法返回。
为了对此进行测试,我创建了一个玩具 activity、MyTestActivity,它使用字符串参数 "myCollection" 和 "myDocument" 调用上述 AsyncTask 和
在 TextView 中显示此文档上次更新的值。现在,TextView 不再显示实际值“2019-10-03”,而是显示值“1970-01-01”,这是
在 doInBackground 中用于初始化返回的 String 变量。就好像 doInBackground 懒得等到文档被阅读了。代码如下。
public class MyTestActivity extends AppCompatActivity{
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_test);
button = findViewById(R.id.update_button);
textView = findViewById(R.id.update_text_view);
}
public void buttonClicked(View view) throws ExecutionException, InterruptedException {
UpdateTask task = new UpdateTask(this, "myCollection", "myDocument");
String date = task.execute().get();
textView.setText("Last update on "+date);
}
private static class UpdateTask extends AsyncTask<Integer, Integer, String> {
private WeakReference<MyTestActivity> activityWeakReference;
String collection;
String document;
String lastUpdate;
UpdateTask(MyTestActivity activity, String collection, String document) {
activityWeakReference = new WeakReference<MyTestActivity>(activity);
this.collection = collection;
this.document = document;
lastUpdate = new String();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
MyTestActivity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
}
@Override
protected String doInBackground(Integer... params) {
FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference noteRef = db.collection(collection).document(document);
lastUpdate = "1970-01-01";
noteRef.get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
@Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists()) {
Map<String, Object> map = documentSnapshot.getData();
lastUpdate = (String)map.get("last update");
activityWeakReference.get().textView.setText(lastUpdate);
} else {
lastUpdate = "Document doesn't exist";
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
lastUpdate = "Listener failed.";
}
});
return lastUpdate;
}
}
}
谁能解释一下这是怎么回事?
I have a database in Firebase Firestore where each document has a particular key "last update" with value, a String, representing a date in the form YYYY-MM-DD.
将日期存储为字符串并不常见,您应该将其存储为:
FieldValue.serverTimestamp()
正如我在以下 post 的回答中所解释的:
So I decided to defer it to an AsyncTask.
Cloud Firestore 数据库客户端已在后台线程中运行所有网络操作。这意味着所有操作都不会阻塞您的主线程。将它添加到 AsyncTask
中根本不会带来任何好处。
Now, instead of showing the actual value, "2019-10-03", the TextView displays the value, "1970-01-01", which is the one used in doInBackground
发生这种情况是因为您正试图从一个异步方法 return 同步发送一条消息。那不是一个好主意。您应该按预期异步处理 API。
一个快速解决这个问题的方法是只在 onSuccess()
方法中使用 lastUpdate
的值,否则我建议你从这个 中看到我的答案的最后一部分 in which I have explained how it can be done using a custom callback. You can also take a look at this video 以便更好地理解。
哎呀!那是糟糕的设计。 Firestore 调用是异步的,因此您无需将它们放入 asyncTask 后台方法中。此外,使用同步任务不会更快地执行您的代码。您需要的是 "loading message",直到您的 OnSuccessListener 返回。
我在 Cloud Firestore 中有一个数据库,其中每个文档都有一个特定的键 "last update" 和值,一个字符串,表示 YYYY-MM-DD 格式的日期。每次更新文档时,"last update" 的值被设置为更新日期。
现在,我希望我的 activity 有一个方法来检查文档的最后更新。由于文档包含相当大的对象列表,因此此更新检查需要几秒钟。所以我决定将它推迟到 AsyncTask。 AsyncTask 的 doInBackground 方法应该为文档创建一个 DocumentReference,noteRef,并用 noteRef.get() 读取它的 "last update",配备 onSuccess- 和 onFailure 侦听器,转换为一个字符串,然后由该方法返回。
为了对此进行测试,我创建了一个玩具 activity、MyTestActivity,它使用字符串参数 "myCollection" 和 "myDocument" 调用上述 AsyncTask 和 在 TextView 中显示此文档上次更新的值。现在,TextView 不再显示实际值“2019-10-03”,而是显示值“1970-01-01”,这是 在 doInBackground 中用于初始化返回的 String 变量。就好像 doInBackground 懒得等到文档被阅读了。代码如下。
public class MyTestActivity extends AppCompatActivity{
private Button button;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_test);
button = findViewById(R.id.update_button);
textView = findViewById(R.id.update_text_view);
}
public void buttonClicked(View view) throws ExecutionException, InterruptedException {
UpdateTask task = new UpdateTask(this, "myCollection", "myDocument");
String date = task.execute().get();
textView.setText("Last update on "+date);
}
private static class UpdateTask extends AsyncTask<Integer, Integer, String> {
private WeakReference<MyTestActivity> activityWeakReference;
String collection;
String document;
String lastUpdate;
UpdateTask(MyTestActivity activity, String collection, String document) {
activityWeakReference = new WeakReference<MyTestActivity>(activity);
this.collection = collection;
this.document = document;
lastUpdate = new String();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
MyTestActivity activity = activityWeakReference.get();
if (activity == null || activity.isFinishing()) {
return;
}
}
@Override
protected String doInBackground(Integer... params) {
FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference noteRef = db.collection(collection).document(document);
lastUpdate = "1970-01-01";
noteRef.get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
@Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if (documentSnapshot.exists()) {
Map<String, Object> map = documentSnapshot.getData();
lastUpdate = (String)map.get("last update");
activityWeakReference.get().textView.setText(lastUpdate);
} else {
lastUpdate = "Document doesn't exist";
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
lastUpdate = "Listener failed.";
}
});
return lastUpdate;
}
}
}
谁能解释一下这是怎么回事?
I have a database in Firebase Firestore where each document has a particular key "last update" with value, a String, representing a date in the form YYYY-MM-DD.
将日期存储为字符串并不常见,您应该将其存储为:
FieldValue.serverTimestamp()
正如我在以下 post 的回答中所解释的:
So I decided to defer it to an AsyncTask.
Cloud Firestore 数据库客户端已在后台线程中运行所有网络操作。这意味着所有操作都不会阻塞您的主线程。将它添加到 AsyncTask
中根本不会带来任何好处。
Now, instead of showing the actual value, "2019-10-03", the TextView displays the value, "1970-01-01", which is the one used in doInBackground
发生这种情况是因为您正试图从一个异步方法 return 同步发送一条消息。那不是一个好主意。您应该按预期异步处理 API。
一个快速解决这个问题的方法是只在 onSuccess()
方法中使用 lastUpdate
的值,否则我建议你从这个 中看到我的答案的最后一部分
哎呀!那是糟糕的设计。 Firestore 调用是异步的,因此您无需将它们放入 asyncTask 后台方法中。此外,使用同步任务不会更快地执行您的代码。您需要的是 "loading message",直到您的 OnSuccessListener 返回。