【问题标题】:Why does the command transaction.update is executed before the carrelloAttuale.prodotti.add() command为什么命令transaction.update在carrelloAttuale.prodotti.add()命令之前执行
【发布时间】:2019-07-27 10:40:49
【问题描述】:

我正在尝试从云存储库的文档中获取产品,然后将该产品放入购物车。当我(成功)阅读产品时,我尝试将其放入在外部声明的数组列表中,但除非我将 final 放入变量,否则它不起作用。 这样做,当我运行下面的代码时,我成功地检索到了数据,但是操作 carrelloAttuale.prodotti.add(prod) 是在命令 transaction.update() 之后执行的,所以更新不会上传与开始没有什么不同.

//prendo l'utente
                FirebaseAuth auth= FirebaseAuth.getInstance();

                //mi salvo il codice del prodotto scannerizzato
                final String codiceProdottoScannerizzato=String.valueOf(intentData);
                final FirebaseFirestore db = FirebaseFirestore.getInstance();
                final DocumentReference docRef = db.collection("carrelli").document(auth.getUid());
                final DocumentReference docrefprodotti = db.collection("prodotti").document(codiceProdottoScannerizzato);
                db.runTransaction(new Transaction.Function<Void>() {
                    @Override
                    public Void apply(Transaction transaction) throws FirebaseFirestoreException {
                        DocumentSnapshot snapshot = transaction.get(docRef);
                        final Carrello carrelloAttuale = snapshot.toObject(Carrello.class);

                        docrefprodotti.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                            @Override
                            public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                                if (task.isSuccessful()) {
                                    DocumentSnapshot document = task.getResult();
                                    if (document.exists()) {
                                        Prodotti prod=document.toObject(Prodotti.class);
                                        prod.id=codiceProdottoScannerizzato;
                                        prod.totalePezziCarrello=1;
                                        carrelloAttuale.prodotti.add(prod);
                                        Log.d(TAG, "PRODOTTO: " + prod.toString());
                                    } else {
                                        Log.d(TAG, "No such document");

                                    }
                                } else {
                                    Log.d(TAG, "get failed with ", task.getException());
                                }
                            }
                        });

                        Log.d(TAG, "CARRELLO FB: " + carrelloAttuale.size());
                        transaction.update(docRef, "prodotti", carrelloAttuale.getProdotti());

                        // Success
                        return null;
                    }
                }).addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        Log.d(TAG, "Transaction success!");
                    }
                })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.w(TAG, "Transaction failure.", e);
                            }
                        });

我希望在 carrelloAttuale.prodotti.add(prod) 之后执行命令更新 在调试日志中,标签的顺序是: 卡雷罗 FB: 0 产品:名称:拿铁

【问题讨论】:

    标签: java android google-cloud-firestore


    【解决方案1】:

    数据是从 Firestore 异步加载的,因为它可能必须从服务器中检索。为防止阻止应用程序,主代码在检索数据时继续。然后当数据可用时,您的onComplete 会被调用。

    这意味着任何需要从数据中获取数据的代码,必须在onComplete 方法内,或者从那里调用。所以像:

    docrefprodotti.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if (task.isSuccessful()) {
                DocumentSnapshot document = task.getResult();
                if (document.exists()) {
                    Prodotti prod=document.toObject(Prodotti.class);
                    prod.id=codiceProdottoScannerizzato;
                    prod.totalePezziCarrello=1;
                    carrelloAttuale.prodotti.add(prod);
                    Log.d(TAG, "PRODOTTO: " + prod.toString());
                } else {
                    Log.d(TAG, "No such document");
    
                }
            } else {
                Log.d(TAG, "get failed with ", task.getException());
            }
    
            Log.d(TAG, "CARRELLO FB: " + carrelloAttuale.size());
            transaction.update(docRef, "prodotti", carrelloAttuale.getProdotti());
        }
    });
    

    另见:

    【讨论】:

    • 我试过你的方法,但我必须声明最终交易,这会在我运行应用程序时导致崩溃。谢谢顺便说一句,我解决了在 onComplete 函数内部调用一个执行事务的自定义函数
    • 我不太明白这里的“声明最终交易”是什么意思。你能显示你得到的代码和错误消息和堆栈跟踪吗?
    【解决方案2】:

    “命令更新”在调用“carrelloAttuale.prodotti.add(prod)”之前执行,因为onComplete() 方法具有异步行为并立即返回。这意味着侦听器将在数据库更新操作完成后的一段时间后才会被调用。无法保证需要多长时间。根据您的连接速度和状态,完成更新操作可能需要几百毫秒到几秒钟。

    如果您想对该数据使用某些逻辑,则必须等到异步 Firebase 数据库操作完成。这意味着您只能在侦听器回调本身内使用prod 对象。

    有关更多信息,我建议您查看此 post 的答案的最后一部分,其中我解释了如何使用自定义回调来完成。您也可以看看这个 video 以获得更好的理解。

    【讨论】:

    • 感谢您的帮助,现在我了解了这些方法的行为,我已经成功地将我的数据传递到了一个执行我想要的函数的函数中。现在我想弄清楚交易失败的原因,但这是另一个问题。
    • 很高兴听到它有效。是的,这听起来是另一个问题,基本上应该被视为另一个问题。因此,请使用自己的 MCVE 发布另一个新问题,以便我和其他 Firebase 开发人员可以帮助您。
    猜你喜欢
    • 2019-10-05
    • 1970-01-01
    • 2023-03-23
    • 2014-04-10
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2020-09-06
    相关资源
    最近更新 更多