草庐IT

android - 递归导致 mutableData.setValue() 导致在 backstack 中产生相同的 Activity ?

coder 2023-06-08 原文

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


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

Campaigns{
   UNQ_KEY: 1 //This is being set in the transaction
}

而不是这个:

Campaigns{
   UNQ_KEY:{
    count: 1 //this is being set in the transaction
  }
}

问题没有发生

所以,总而言之,这可能是一个递归错误。


我有这个 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());
        }
    });

这一行:

mutableData.child("users").child(getUid()).child("count").setValue(userIncrementedInt);

还有这个:

mutableData.child("count").setValue(incrementedTotalCount);

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

每次点击按钮,backstack都会产生一个新的activity(有问题的activity)。

为了向您展示它的外观,这里有一个 GIF:

为什么会这样?

最佳答案

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

未找到解决方案。

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

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

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



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


I tried to debug. It wasn't activated on any of these lines. It takes me to a bunch of Android files (such as View.java). When I "Run to cursor" (skip the next debug breakpoint), it restarts.

你能不能试试看runnable里面点击的view是否不为null?

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解释这是如何工作的:

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>

In addition, you can set instances of your own class into this location, provided they satisfy the following constraints:

The class must have a default constructor that takes no arguments The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized

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

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

更新 2:

您的数据架构看起来像这样吗?

{
    "campaings": {
        "key": {
            "count": "1",
            "users": {
                "-JRHTHaIs-jNPLXOQivY": {
                    "count": "1",
                    ...
                },
                ...
            }
            ...
        },
        "other-key": {
            ...
        }
        ...
    }
}

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

// 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

来自 documentation :

doTransaction() will be called multiple times and must be able to handle null data. Even if there is existing data in your remote database, it may not be locally cached when the transaction function is run.

尝试更改此部分:

  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:如果在可预见的将来有人可能会解决类似这样的问题,我将离开解决方案

关于android - 递归导致 mutableData.setValue() 导致在 backstack 中产生相同的 Activity ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39796097/

有关android - 递归导致 mutableData.setValue() 导致在 backstack 中产生相同的 Activity ?的更多相关文章

  1. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  2. ruby - 在匿名 block 中产生 - 2

    我没有理解以下行为(另请参阅inthisSOthread):defdef_testputs'def_test.in'yieldifblock_given?puts'def_test.out'enddef_testdoputs'def_testok'endblock_test=procdo|&block|puts'block_test.in'block.callifblockputs'block_test.out'endblock_test.calldoputs'block_test'endproc_test=procdoputs'proc_test.in'yieldifblock_gi

  3. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  4. ruby-on-rails - 优雅的 Rails : multiple routes, 相同的 Controller Action - 2

    让多条路线去同一条路的最优雅的方式是什么ControllerAction?我有:get'dashboard',to:'dashboard#index'get'dashboard/pending',to:'dashboard#index'get'dashboard/live',to:'dashboard#index'get'dashboard/sold',to:'dashboard#index'这很丑陋。有什么“更优雅”的建议吗?一个类轮的奖励积分。 最佳答案 为什么不只有一个路由和一个Controller操作,并根据传递给它的参数来

  5. Ruby 守护进程导致 ActiveRecord 记录器 IOError - 2

    我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame

  6. ruby - 从另一个私有(private)方法中使用 self.xxx() 调用私有(private)方法 xxx,导致错误 "private method ` xxx' called” - 2

    我正在尝试获得良好的Ruby编码风格。为防止意外调用具有相同名称的局部变量,我总是在适当的地方使用self.。但是现在我偶然发现了这个:classMyClass上面的代码导致错误privatemethodsanitize_namecalled但是当删除self.并仅使用sanitize_name时,它会起作用。这是为什么? 最佳答案 发生这种情况是因为无法使用显式接收器调用私有(private)方法,并且说self.sanitize_name是显式指定应该接收sanitize_name的对象(self),而不是依赖于隐式接收器(也是

  7. ruby-on-rails - 获取并发布相同匹配项的请求 - 2

    在我的路线文件中我有:match'graphs/(:id(/:action))'=>'graphs#(:action)'如果是GET请求(工作)或POST请求(不工作),我想匹配它我知道我可以使用以下方法在资源中声明POST请求:post'/'=>:show,:on=>:member但是我怎样才能为比赛做到这一点呢?谢谢。 最佳答案 如果你同时想要POST和GETmatch'graphs/(:id(/:action))'=>'graphs#(:action)',:via=>[:get,:post]编辑默认值可以设置如下match'g

  8. ruby - 递归地将所有数字字符串转换为 Ruby 哈希中的整数 - 2

    我有一个随机大小的散列,它可能有类似"100"的值,我想将其转换为整数。我知道我可以使用value.to_iifvalue.to_i.to_s==value来做到这一点,但我不确定我将如何在我的散列中递归地做到这一点,考虑到一个值可以是一个字符串,或一个数组(哈希或字符串),或另一个哈希。 最佳答案 这是一个非常简单的递归实现(尽管必须同时处理数组和散列会增加一些技巧)。deffixnumifyobjifobj.respond_to?:to_i#IfwecancastittoaFixnum,doit.obj.to_ielsifobj

  9. Ruby:标准递归模式 - 2

    我经常迷上ruby​​的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情

  10. ruby - 为什么 return 关键字会导致我的 'if block' 出现问题? - 2

    下面的代码工作正常:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson)do|key,oldv,newv|ifkey==:aoldvelsifkey==:bnewvelsekeyendendputskerson.inspect但是如果我在“ifblock”中添加return,我会得到一个错误:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson

随机推荐