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:
为什么会这样?
(我将在这里发帖,因为这样更容易管理我的评论)...
未找到解决方案。
*更新 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:如果在可预见的将来有人可能会解决类似的问题,我将留下解决方案