编辑:2016年10月23日:未解决,我仍在寻找答案。我将重写这个问题,使其更加清晰,因为我现在知道造成这个问题的原因。
编辑:2016年10月26日:发现的事情:在尝试找到问题时,我收到了一个帮助我找到问题的错误。事实证明,如果我在Firebase数据库中有这个错误:
c:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe -ExecutionPolicy RemoteSigned -Command .\.git\hooks\pre-commit.ps1
而不是:
Campaigns{
UNQ_KEY: 1 //This is being set in the transaction
}
问题不会发生 。
因此,总之,它可能是一个递归错误。
我有这个Firebase交易:
Campaigns{
UNQ_KEY:{
count: 1 //this is being set in the transaction
}
}
这一行:
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());
}
});
和这一个:
mutableData.child("users").child(getUid()).child("count").setValue(userIncrementedInt);
当我运行事务时,会再次创建相同的活动并打开。当我单击后退按钮时,它将转到backstack中的上一个活动。但是,后台的先前活动本身就是同一活动。像这样:
每次单击按钮,都会在backstack中生成一个新活动(有问题的活动)。
为了向您展示它的样子,这里是一个GIF:
为什么会这样?
答案 0 :(得分:1)
它会重新启动您的活动,因为它会在某处崩溃。试试这段代码:
public void onClick(View v) {
if (mp == null){
mp = new MediaPlayer();
} else {
mp.reset();
}
try {
AssetFileDescriptor afd;
afd = getAssets().openFd("click.mp3");
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp.prepare();
mp.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e){
} catch (IOException e){
} catch (Exception e){
}
v.setEnabled(false);
final View clicked = v;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
clicked.setEnabled(true);
}
};
handler.postAtTime(runnable,System.currentTimeMillis()+100);
handler.postDelayed(runnable,100);
}
答案 1 :(得分:1)
(我会在这里张贴,因为它更容易管理我的评论)...
找不到解决方案。
*更新4:找到解决方案**
经过多次尝试和大量评论后,终于找到了解决方案,显然OP在另一个类中有增量方法,并将其移动到用于解决问题的同一个类。
至于为什么会发生这种情况,在我看来,也许它与交易上的并发问题有关,也许问题在于它自己创建了一个循环。您的活动开始了,稍后您实例化FirebaseController
,在某些时候,它会启动increment
方法,最终执行异步执行(以某种方式失败?)并再次启动您的活动< /秒>
请参阅下面的失败(但是问题排查步骤)尝试
我试着调试。它没有在任何这些线上激活。它需要 我来了一堆Android文件(比如View.java)。当我&#34;跑到 光标&#34; (跳过下一个调试断点),它重新启动。
您是否可以尝试检查runnable中单击的视图是否为空?
Runnable runnable = new Runnable() {
@Override
public void run() {
// if not null do this
clicked.setEnabled(true);
// if null print some log
// ...
}
};
您在调试时是使用Step Into还是Step over(如果您深入了解可能使用Step Into(F5)的类的层次结构,是否可以尝试使用Step Over(F6)进行调试)?
如果我们找到答案,我会在这里发布:
更新1:
MutableData#setValue(java.lang.Object)
documentation解释了这是如何工作的:
将此位置的数据设置为给定值。原生类型 此方法接受的值对应于JSON类型:
Boolean
Long
Double
Map<String, Object>
List<Object>
此外,您可以将自己的类的实例设置到此位置,前提是它们满足以下约束条件:
该类必须具有不带参数的默认构造函数 class必须为要分配的属性定义公共getter。 没有公共getter的属性将设置为其默认值 当一个实例被反序列化时
尝试使用其他开发人员建议的其他数据类型:
将#setValue
参数更改为上面列表中的对象,#getValue
也返回一个对象,尝试强制转换为正确的类型,也许你可以使用Integer
类
更新2:
您的数据架构看起来像这样吗?
{
"campaings": {
"key": {
"count": "1",
"users": {
"-JRHTHaIs-jNPLXOQivY": {
"count": "1",
...
},
...
}
...
},
"other-key": {
...
}
...
}
}
这就是我从那里的代码中推断的,如果我犯了错误,你可以澄清我。
// 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");
}
});
代码示例的目的是说明您正在进行的数据模式搜索(如果我犯了错误,再次在任何部分纠正我),但请放置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);
}
类似于:
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);
}
P.S:如果任何人在可预见的未来可能会对类似的事情进行排查,我会离开解决方案
答案 2 :(得分:1)
也许它正试图启动毫无准备的媒体播放器。像这样开始:
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener(){
public void onPrepared(MediaPlayer p){
p.start();
}
}
修改强>
查看Firebase doc MutableData setValue(..)方法,它只接受以下类型。但是你使用的是原始类型的int。
所以你应该改变这个
int totalCount = mutableData.child("count").getValue(int.class);
与
Long totalCount = mutableData.child("count").getValue();
答案 3 :(得分:0)
在这一行中,
mutableData.child("count").setValue(newTotalCount);
你正在通过一个&#39; int&#39; setValue()方法的值。它应该是此方法支持的Object。
public void setValue (Object value)
Set the data at this location to the given value.
The native types accepted by this method for the value correspond to the JSON types:
Boolean
Long
Double
Map<String, Object>
List<Object>
你正在传递一个&#39; int&#39;那里的价值。所以将该值更改为相应的Object。
在这一行中,
int totalCount = mutableData.child("count").getValue(int.class);
你正在通过&#39; int.class&#39;获得价值。它不是一个对象。它也应该是一个对象。改变这个。我希望它会对你有所帮助。