导致mutableData.setValue()的递归导致在backstack中生成相同的活动?

Ab_*_*Ab_ 18 android firebase firebase-realtime-database

编辑:2016年10月23日:这还没有解决,我仍在寻找答案.我将重写这个问题以使其更清晰,因为我现在知道是什么导致了这个问题.


编辑:2016年10月26日:发现的事情:在尝试找到问题时,我找到了一个帮助我找到问题的错误.事实证明,如果我在Firebase数据库中有这个:

Campaigns{
   UNQ_KEY: 1 //This is being set in the transaction
}
Run Code Online (Sandbox Code Playgroud)

而不是这个:

Campaigns{
   UNQ_KEY:{
    count: 1 //this is being set in the transaction
  }
}
Run Code Online (Sandbox Code Playgroud)

问题不会发生.

所以,总之,它可能是一个递归错误.


我有这个Firebase交易:

database.runTransaction(new Transaction.Handler() {
        @Override
        public Transaction.Result doTransaction(MutableData mutableData) {
            Long preUserIncrementedInt = Long.parseLong(b.getText().toString());
            Long userIncrementedInt = ++preUserIncrementedInt;
            mutableData.child("users").child(getUid()).child("count").setValue(userIncrementedInt);
            Long preIncrementedTotalCount = mutableData.child("count").getValue(Long.class);
            Long incrementedTotalCount = ++preIncrementedTotalCount;
            mutableData.child("count").setValue(incrementedTotalCount);
            return Transaction.success(mutableData);
        }

        @Override
        public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
            if (databaseError != null)
                Log.wtf(TAG,databaseError.getMessage());
        }
    });
Run Code Online (Sandbox Code Playgroud)

这一行:

mutableData.child("users").child(getUid()).child("count").setValue(userIncrementedInt);
Run Code Online (Sandbox Code Playgroud)

还有这个:

mutableData.child("count").setValue(incrementedTotalCount);
Run Code Online (Sandbox Code Playgroud)

当我运行事务时,会再次创建相同的活动并打开.当我单击后退按钮时,它将转到backstack中的上一个活动.但是,后台的先前活动本身就是同一活动.像这样:

图片

每次单击该按钮时,都会在backstack中生成一个新活动(带有问题的活动).

为了向您展示它的样子,这是一个GIF:

GIF

为什么会这样?

Iva*_*que 1

(我将在这里发帖,因为这样更容易管理我的评论)...

未找到解决方案。

*更新 4:找到解决方案**

经过多次尝试和大量评论,终于找到了解决方案,显然OP在另一个类中具有增量方法,并将其移动到正在使用的同一个类中解决了问题。

至于为什么会发生这种情况,在我看来,也许与事务的并发问题有关,也许问题在于它自己创建了一个循环。您的活动开始,稍后您实例化了您的FirebaseController活动,在某个时刻,触发了该increment方法,进行异步执行,最终结束(以某种方式失败?)并再次启动您的活动



请参阅下面的失败(但故障排除步骤)尝试


我尝试调试。它没有在任何这些线路上激活。它带我到一堆 Android 文件(例如 View.java)。当我“运行到光标”(跳过下一个调试断点)时,它会重新启动。

您可以尝试检查可运行内的单击视图是否不为空吗?

Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // if not null do this
            clicked.setEnabled(true);
            // if null print some log
            // ...
        }
    };
Run Code Online (Sandbox Code Playgroud)

调试时您是否使用 Step Into 或 Step over(如果您更深入地了解可能使用 Step Into (F5) 的类层次结构,您可以尝试使用 Step Over (F6) 进行调试)吗?

如果我们找到答案,我会将其发布在这里:

更新1:

MutableData#setValue(java.lang.Object)文档解释了它是如何工作的:

将此位置的数据设置为给定值。此方法接受的值的本机类型对应于 JSON 类型:

Boolean
Long
Double
Map<String, Object>
List<Object>

此外,您可以将自己的类的实例设置到此位置,前提是它们满足以下约束:

该类必须有一个不带参数的默认构造函数 该类必须为要分配的属性定义公共 getter。反序列化实例时,没有公共 getter 的属性将被设置为其默认值

尝试使用其他开发人员建议的另一种数据类型:

将参数更改#setValue为上面列表中的对象并#getValue 返回一个对象,尝试转换为正确的类型,也许你可以使用Integer

更新2:

您的数据模式看起来像这样吗?

{
    "campaings": {
        "key": {
            "count": "1",
            "users": {
                "-JRHTHaIs-jNPLXOQivY": {
                    "count": "1",
                    ...
                },
                ...
            }
            ...
        },
        "other-key": {
            ...
        }
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我从那里的代码片段推断出来的,如果我犯了错误,你可以澄清我。

// here we are searching for the current reference in Campaings/key
DatabaseReference database = FirebaseDatabase.getInstance().getReference().child("Campaigns").child(key);

int preIncrementUserCount = Integer.parseInt(button.getText().toString());
final int incrementedUserCount = ++preIncrementUserCount;

button.setText(String.valueOf(incrementedUserCount));
database.runTransaction(new Transaction.Handler() {
    @Override
    public Transaction.Result doTransaction(MutableData mutableData) {

        // here we are searching for the current count value in 
        // Campaings/key/count
        Integer currentValue = mutableData.child("count").getValue(Integer.class);

        if (currentValue == null) {
            // do something...
        } else {
            // here we are setting the count value in Campaings/key/count
            mutableData.child("count").setValue(++currentValue);
        }

        // here we are setting the count value in Campaings/key/users/UUID/count
        mutableData.child("users").child(getUid()).child("count").setValue(incrementedUserCount);

        return Transaction.success(mutableData);
    }

    @Override
    public void onComplete(DatabaseError databaseError, boolean committed, DataSnapshot dataSnapshot) {

       if (databaseError != null) {
            Log.e(TAG, "Error: " + databaseError.getMessage());
       }

       System.out.println("Transaction completed");
    }
});
Run Code Online (Sandbox Code Playgroud)

代码示例的目的是说明您正在执行的数据模式搜索(再次,如果我犯了错误,请在任何部分纠正我),但请打开databaseError日志onComplete以进行调试

更新3

文档中:

doTransaction() 将被多次调用,并且必须能够处理空数据。即使您的远程数据库中存在现有数据,当事务功能运行时,也可能不会在本地缓存该数据。

尝试更改这部分:

  if (currentValue == null) {
      // do something...
  } else {
      // here we are setting the count value in Campaings/key/count
      mutableData.child("count").setValue(++currentValue);
  }
Run Code Online (Sandbox Code Playgroud)

对于类似的事情:

  if (mutableData.child("count").getValue() == null) {
      // print something...
      // Log.d(TAG,"Value at some point was null");
      // or maybe (just to test)
      // mutableData.child("count").setValue(1);
  } else {
      // here we are setting the count value in Campaings/key/count
      mutableData.child("count").setValue(++currentValue);
  }
Run Code Online (Sandbox Code Playgroud)

PS:如果在可预见的将来有人可能会解决类似的问题,我将留下解决方案