当前位置: 首页 > 知识库问答 >
问题:

从AsyncTask事务访问Firebase数据库

谈灵均
2023-03-14
public class MyAsyncTask extends AsyncTask<String,Void,Void> {

    @Override
    protected Void doInBackground(String... params) {
        String para1 = params[0];
        String para2 = params[1];

        performCalculations(para1,para2);

        return null;
    }

    public void performCalculation(String para1, String para2) {
        DatbaseReference ref = FirebaseDatabase.getInstance().getReference().child(para1);

        // Run the transaction here
        ref.runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {

                 TaskCompletionSource<DataSnapshot> taskCompletionSource = new TaskCompletionSource<>();

                 DatabaseReference ref2 = FirebaseDatabase.getInstance().getReference().child(param2);

                 ref2.addListenerForSingleValueEvent(new MyValueEventListener(taskCompletionSource));

                 try {
                    dataSnapshot = Tasks.await(taskCompletionSource.getTask());

                    // DOING SOME AWESOME THINGS HERE 
                    // And updating the mutable Data


                } catch (ExecutionException | InterruptedException e) {
                    Log.v(TAG, "Exception Catched");
                    e.printStackTrace();
                }


                mutableData.setValue(stats);
                return Transaction.success(mutableData);
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
                if (databaseError != null) {
                    Log.d(TAG, "onComplete: Error: " + databaseError.getMessage());
                } else {
                    Log.d(TAG, "onComplete: Transaction was successful");

                }
            }

        }
    }

    private class MyValueEventListener implements ValueEventListener {

        private final TaskCompletionSource<DataSnapshot> taskSource;

        public MyValueEventListener(TaskCompletionSource<DataSnapshot> taskSource) {
            this.taskSource = taskSource;
        }

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            Log.v(TAG, "Looks like MyValueEventListener received the data");
            taskSource.setResult(dataSnapshot);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.v(TAG, "Looks like MyValueEventListener thrown an error");
            taskSource.setException(databaseError.toException());
        }

    }

}

把日志放在各处,我发现它到达了tasks.await语句。但是,ondatachanged回调从未被调用。

它卡在那一点上。没有错误。没有例外。

最大的问题是,从那时起,它停止了整个应用程序的所有回调。我的所有活动都被阻止了,因为它从不调用ondatachanged。看起来它在内部崩溃或被线程阻塞。

public class MyAsyncTask extends AsyncTask<String,Void,Void> {

    DataSnapshot mDataSnapshot;

    ValueEventListener mListener;

    DatabaseReference ref2;

   @Override
    protected Void doInBackground(String... params) {
        String para1 = params[0];
        String para2 = params[1];

        performCalculations(para1,para2);

        return null;
    }

    public void performCalculation(String para1, String para2) {

            TaskCompletionSource<DataSnapshot> taskCompletionSource = new TaskCompletionSource<>();

            ref2 = FirebaseDatabase.getInstance().getReference().child(param2);

            ref2.addListenerForSingleValueEvent(new MyValueEventListener(taskCompletionSource));

            try {
                    // Get the data first time before you proceed
                    dataSnapshot = Tasks.await(taskCompletionSource.getTask());

             } catch (ExecutionException | InterruptedException e) {
                    Log.v(TAG, "Exception Catched");
                    e.printStackTrace();
             }

             // Register the value event listener to keep the data updated
             mListener = new ValueEventListener() {
             @Override
             public void onDataChange(DataSnapshot dataSnapshot) {
                mDataSnapshot = dataSnapshot
                Log.v(TAG, "Data updated");
             }

             @Override
             public void onCancelled(DatabaseError databaseError) {

             }
         };

        ref2.addValueEventListener(mListener);


        DatbaseReference ref = FirebaseDatabase.getInstance().getReference().child(para1);

        // Run the transaction here
        ref.runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {

                 // Perform some stuff based on mDataSanpshot



                mutableData.setValue(stats);
                return Transaction.success(mutableData);
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
                if (databaseError != null) {
                    Log.d(TAG, "onComplete: Error: " + databaseError.getMessage());
                } else {
                    Log.d(TAG, "onComplete: Transaction was successful");
                    ref2.removeEventListener(mListener);
                }
            }

        }
    }

    // My value event listener here ... 

}

共有1个答案

公沈浪
2023-03-14

您可能会从Firebaser(如Fvp)那里得到更知情的答案。在此之前,我要说的是,我非常肯定您在runtransaction()中等待的任务正在创建死锁。您可以看到通过log语句运行回调的线程,如下所示:

Log.i(TAG, "doTransaction: " + Thread.currentThread().getName());

doTransaction()FirebaseDatabaseWorker线程上运行。侦听器回调在主(UI)线程上运行,并且(我猜)是由从DB工作线程派发的事件驱动的。

阻止DB工作线程将导致侦听器回调永远不会激发。任务从未完成,因此task.await()从未释放。

 类似资料:
  • 当需要从数据库中返回一些数据,然后使用它进行一些计算并将其存储回来时,则需要使用事务性数据。 下面来看看运动员列表中的运动员。 我们要检索属性,添加年龄增加岁并将其返还给Firebase。 从集合中检索年龄,然后可以使用事务方法。 我们将获得当前的年龄,增加一年,并更新集合。 如果运行这个代码,可以看到年龄值更新为。如下图所示 -

  • 我正在向用户发送动态通知。因此,我正在处理Firebase云函数。这里是我的问题:我如何访问云功能端的数据库? 这是我的代码: 正如你们所看到的,首先,我想从nofications集合中获取电子邮件,然后使用该电子邮件,我想搜索正在使用该电子邮件的用户,然后,我想获取用户deviceToken。 我尝试了很多关于语法的东西,但没有得到任何结果:/ 同样,我也犯了一些错误: 在这里您可以看到错误:

  • 我目前有一个类似以下的数据库结构。如果无法在Firebase实时数据库安全规则中循环,我如何基于用户对多个组的访问来保护数据?要遵循的例子... 数据库结构: 我如何在上指定安全规则,以基于中指定的任何组与当前用户的

  • 问题内容: 我有一个要求,即只能从本地主机访问mysql数据库。我必须实现一个可以访问数据库的servlet,以允许该系统中的其他服务器访问数据(servlet可以充当代理)。但是,此系统由一个远程服务器组成,该服务器下载执行以下语句的大部分数据: 有人可以建议我如何编写一个以有效方式流式传输此类数据的servlet吗(我是数据库新手)? 问题答案: 首先,我不建议为此使用servlet。有关正确

  • 正如你所见,这个过程非常简单。将引发一个信号事件,并将提供给该信号事件的数据映射到对象。在下面的脚本任务中,我向控制台写入一条消息,并尝试编写对象的测试属性数据内容,以测试事件数据的处理。 我使用单元测试来测试我的过程: 然而,我在控制台输出中得到的只是消息。你能解释一下我哪里错了吗? > 这个过程的建模有问题吗?我已经创建了数据对象,我相信它可以保存事件的数据。编辑:我还将信号输入数据映射到相应

  • 这是我的用户。kt 我做错了什么?