Rx-java通过引用传递或传递值?

时间:2015-08-18 04:23:44

标签: android rx-java

在java方法everything is passed-by-value so i can change the object attributes passed to the method and expect that the original object attributes are changed中。但在这种方法中,我得到了不同的结果:

我有这个方法:

public Observable<Menu> makeMenu(Menu menu, NumberSettingChanges.MenuChanges changes) {
    // Start flow with added and edited extensions
    return Observable.from(changes.added.entrySet())
            .mergeWith(Observable.from(changes.edited.entrySet()))
                    //Upload announcement voices or do nothing if extension is not an announcement
            .flatMap(e -> {
                        if (AppTypeContract.APP_TYPE_ANNOUNCEMENT.equals(e.getValue().type)) {
                            return mMediaManager.uploadAsync(e.getValue().config.localPrompt)
                                    .doOnNext(response -> {
                                        //Update extension prompt with the storage path.
                                        menu.config.extensions.get(e.getKey()).config.prompt = response.mPath;
                                        menu.config.extensions.get(e.getKey()).config.localPrompt = "";
                                    })
                                    .flatMap(response -> Observable.just(e));
                        } else {
                            return Observable.just(e);
                        }
                    }
            )
}

我在flatmap中操作菜单属性:

menu.config.extensions.get(e.getKey()).config.localPrompt = "";

我在同一个类中调用该方法:

public Observable<NumberSetting> saveSettings(NumberSetting o, NumberSetting n) {
    NumberSettingChanges changes = compareNumberSetting(o, n);

    return makeMenu(n.day, changes.day)
            .mergeWith(makeMenu(n.night, changes.night));
    }

最后:

saveSettings(ns, mNumberSettingNew).subscribe();

我的期望是mNumberSettingNew.menu.config.extensions.get(e.getKey()).config.prompt已更改,但此次调用后没有发生任何变化且mNumberSettingNew根本没有变化。

请注意,我确信更改提示行是在调试中完成的。

1 个答案:

答案 0 :(得分:1)

我认为我不能解释Java的参数语义比你在第一段中引用的链接更好(甚至一半),所以我不会尝试。重点是:Java中的所有内容都是通过值传递的(即复制的),但是对象的复制内容不是对象本身,而是对象的引用。换句话说,引用按值传递

关于您的特定问题:是的,如果您将对可变对象的引用传递给某些rx-java代码,则该引用将指向该对象的同一实例。如果您改变实例,那么调用者代码也将能够看到更改,因为它们是在同一实例上进行的。那是因为rx-java仍然只是Java,不能改变该级别的语言语义。

如果没有看到整个代码,我不确定这里会出现什么问题......您何时检查mNumberSettingsNew是否确实在doOnNext中进行了更改?如果您在saveSettings(ns, mNumberSettingNew).subscribe(); uploadAsync之后立即检查,Subscriber可能尚未返回。您可以尝试在subscribe中添加实际scan并检查结果。

更一般地说,我认为你应该在使用rx-java时尽量避免像这样的副作用。您的情况 - 获取输入对象,对该对象应用一组(可能是异步的)更改,并等待更改的输出对象 - 有点棘手,但我认为可以使用Observable.from(changes.added.entrySet()) .mergeWith(Observable.from(changes.edited.entrySet())) .scan(menuBeforeAnyChanges, new Func2<Menu, Change, Menu>() { public Menu call(final Menu previousVersionOfTheMenu, final Change nextChange) { // since I don't know of a version of scan that can return // an Observable you would I think you would have to adapt // your code in here to be fully synchronous - but of // course the scan itself could run asynchronously final newVersionOfTheMenu = previousVersionOfTheMenu.applyChange(nextChange); return newVersionOfTheMenu; } ) 完成。也许是含糊不清的东西:

added

这将采用菜单的原始版本,连续应用editedSubscriber<Menu>和/ emit /每个更新版本菜单的所有更改。因此,您不会产生任何副作用,只需使用last()订阅该观察结果,然后选择reduce菜单即可应用所有更改的菜单。

编辑:哦,我刚刚看到另一个名为scan的方法可以做到这一点:首先last然后takeLast或{{1 }}