Java 使用AsyncTask读取Firestore文档

Java 使用AsyncTask读取Firestore文档,java,android,firebase,android-asynctask,google-cloud-firestore,Java,Android,Firebase,Android Asynctask,Google Cloud Firestore,我在Cloud Firestore中有一个数据库,其中每个文档都有一个特定的键“last update”,其值是一个字符串,表示YYYY-MM-DD格式的日期。每次更新文档时,“last update”的值都设置为更新日期 现在,我希望我的活动有一个方法来检查文档的上次更新。由于文档包含相当大的对象列表,此更新检查需要几秒钟的时间。所以我决定把它推迟到一个异步任务。AsyncTask的doInBackground方法应该为文档创建一个DocumentReference,noteRef,并使用no

我在Cloud Firestore中有一个数据库,其中每个文档都有一个特定的键“last update”,其值是一个字符串,表示YYYY-MM-DD格式的日期。每次更新文档时,“last update”的值都设置为更新日期

现在,我希望我的活动有一个方法来检查文档的上次更新。由于文档包含相当大的对象列表,此更新检查需要几秒钟的时间。所以我决定把它推迟到一个异步任务。AsyncTask的doInBackground方法应该为文档创建一个DocumentReference,noteRef,并使用noteRef.get()读取其“上次更新”,并配备 onSuccess和onFailure侦听器转换为字符串,然后由方法返回

为了测试这一点,我创建了一个玩具活动MyTestActivity,它使用字符串参数“myCollection”和“myDocument”以及 在文本视图中显示此文档上次更新的值。现在,文本视图不再显示实际值“2019-10-03”,而是显示值“1970-01-01”,即 在doInBackground中用于初始化返回的字符串变量。这就好像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;


        }
    }
}
公共类MyTestActivity扩展了AppCompatActivity{
私人按钮;
私有文本视图文本视图;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity\u my\u test);
按钮=findViewById(R.id.update_按钮);
textView=findViewById(R.id.update\u text\u view);
}
public void按钮点击(视图)抛出ExecutionException、InterruptedException{
UpdateTask=新的UpdateTask(这是“myCollection”、“myDocument”);
字符串日期=task.execute().get();
textView.setText(“上次更新日期“+日期”);
}
私有静态类UpdateTask扩展异步任务{
私人WeakReference活动WeakReference;
字符串集合;
字符串文件;
字符串更新;
UpdateTask(MyTestActivity活动、字符串集合、字符串文档){
activityWeakReference=新的WeakReference(活动);
this.collection=collection;
本文件=文件;
lastUpdate=新字符串();
}
@凌驾
受保护的void onPreExecute(){
super.onPreExecute();
MyTestActivity activity=activityWeakReference.get();
if(activity==null | | activity.isFinishing()){
返回;
}
}
@凌驾
受保护字符串doInBackground(整数…参数){
FirebaseFirestore db=FirebaseFirestore.getInstance();
DocumentReference noteRef=db.collection(collection).document(document);
lastUpdate=“1970-01-01”;
noteRef.get()
.addOnSuccessListener(新的OnSuccessListener(){
@凌驾
成功时公共无效(文档快照文档快照){
if(documentSnapshot.exists()){
Map Map=documentSnapshot.getData();
lastUpdate=(String)map.get(“上次更新”);
activityWeakReference.get().textView.setText(lastUpdate);
}否则{
lastUpdate=“文档不存在”;
}
}
})
.addOnFailureListener(新的OnFailureListener(){
@凌驾
public void onFailure(@NonNull异常e){
lastUpdate=“侦听器失败。”;
}
});
返回最新更新;
}
}
}
有人能解释一下这是怎么回事吗

我在Firebase Firestore中有一个数据库,其中每个文档都有一个特定的键“last update”,其值是一个字符串,以YYYY-MM-DD的形式表示日期

将日期存储为字符串是不常见的,而应将其存储为:

FieldValue.serverTimestamp()
正如我在以下帖子的回答中所解释的:

所以我决定把它推迟到一个异步任务

云Firestore数据库客户端已在后台线程中运行所有网络操作。这意味着所有操作都不会阻塞主线程。在
AsyncTask
中添加它不会带来任何好处

现在,文本视图显示的不是实际值“2019-10-03”,而是doInBackground中使用的值“1970-01-01”

发生这种情况是因为您试图从异步方法同步返回消息。那不是个好主意。您应该按照预期异步处理API


这个问题的一个快速解决方法是仅在
onSuccess()方法中使用
lastUpdate
的值,否则我建议您从中查看anwser的最后一部分,其中我已经解释了如何使用自定义回调来完成。您还可以查看此以更好地理解。

哎哟!那是个糟糕的设计。Firestore调用是异步的,所以您不需要将它们放入asyncTask后台方法中。此外,使用synctask不会更快地执行代码。您需要的是一条“加载消息”,直到OnSuccessListener发回。

他使用的是Firebase Firestore而不是实时数据库。但你仍然是对的。@kylexy1357是的,你是对的,但我的回答中什么是指实时数据库?@Alex Mamo:我读了你链接到的帖子并观看了视频。您建议的带有自定义回调的解决方案完成了任务-al