java - 使用 AsyncTask 读取 Firestore 文档

标签 java android firebase android-asynctask google-cloud-firestore

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

现在,我希望我的 Activity 有一个方法来检查文档的上次更新。由于文档包含相当大的对象列表,因此此更新检查需要几秒钟。所以我决定将其推迟到 AsyncTask。 AsyncTask 的 doInBackground 方法应该为文档创建一个 DocumentReference noteRef,并使用 noteRef.get() 读取其“最后更新”,配备 onSuccess- 和 onFailure 监听器转换为 String,然后由该方法返回。

为了测试这一点,我创建了一个玩具 Activity MyTestActivity,它使用字符串参数“myCollection”和“myDocument”调用上述 AsyncTask,并且 在 TextView 中显示该文档上次更新的值。现在,TextView 显示值“1970-01-01”,而不是显示实际值“2019-10-03”,这是 在 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()

正如我在以下帖子的回答中所解释的:

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

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

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

关于java - 使用 AsyncTask 读取 Firestore 文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58231778/

相关文章:

java - 使用 ImageJ 转换图像格式

android - 应用程序中的多个 map Activity

javascript - 使用 ngCordova media/onic/firebase 制作音频播放列表

java - 如何在每次测试 Junit5 TestFX 后启动应用程序

java - .setBackground() 方法不适用于 JRadioButton

Android Copy String 类似Delphi Copy的功能

android - 如何在android中永久设置壁纸

firebase - 由于未捕获的异常 'com.firebase.durabledeeplink' 而终止应用程序,原因 : 'Configure Durable Deep Link fails

javascript - THEN 语句返回 promise /始终返回和一致返回错误

java - 如何从 java keystore 中选择正确的 SSL 证书,以便在相互 TLS 的情况下发送到相应的端点