RxJava - how to get the object from a single without lambdas - android

I'm completely new to RxJava. I am accessing a method that returns a Single<Location>. I need the Location. This is an Android project using Java 1.7, so no lambdas, which is why I'm stuck. Every example and every book that I see uses lambdas. How do I get this Location from the Single without using lambdas?
locationProvider.getLastKnownLocationWithTimeout() // returns Single<Location>
.flatMap(/* what should go here? */);

Here is the signature for Single<T>.flatMap:
public final <R> Single<R> flatMap(Function<? super T,? extends SingleSource<? extends R>> mapper)
where Function is an interface with exactly one method, apply.
So in your case, I believe you need something like
locationProvider.getLastKnownLocationWithTimeout()
.flatMap(new Function<Location, Single<String>>() {
#Override
public Single<String> apply(Location location) {
// apply transformation to e.g. String here
}
});
where the type String is a placeholder and should be changed based on the transformation you're actually trying to accomplish.
Note that this answer was typed outside an IDE so may be missing a brace or two.

Related

Mockito... how to handle a method that creates a new object from an existing one

I have a class with a method which constructs a new object based on the value of an object passed to it.
e.g. Simplified version, hope there's no typos
public class MyLocation extends Location {
...
public MyLocation move(double speed, double dir, int seconds) {
return new MyLocation(getLatitude() + cos(dir)*speed*time, getLongitude() + sin(dir)*speed*time);
}
}
But I get errors from the setters and getters in the Location constructor.
Method setTime in android.location.Location not mocked
Given there's more than one attribute being calculated, I need to return an object that contains them, which will need to be constructed. But since this is a newly constructed object, there's no way to Mock it, unless I put #Mock in the actual code, which I know is a Bad Idea.
I really don't understand why Mock is applied to other classes like Location that I'm not trying to test. Just give me the object back so I can verify that the calculations were correct.
Surely this isn't an uncommon scenario, yet it looks like I'm the only person running into it! Am I stuck in some kind of antiPattern?
I've been round and round in circles on this one, with different constructors, subclasses and static methods and all kinds of groovy things, but I'm just missing the illumination to get me out of this maze.

Is it possible to have databinding generate non-nullable accessors for variables?

I am updating an app that uses the databinding library. I've been going through the breaking changes one by one, and I'm currently stuck on trying to access the binding variables. It looks like the accessors are now annotated with #Nullable, which means I have to use safe calls or assert non-null (which makes the code pretty ugly). Is there another alternative? Is there some sort of databinding setting that lets me change the generated annotations to #NonNull?
Generated code:
public abstract void setVm(#Nullable GeneralSettingsViewModel vm);
#Nullable
public GeneralSettingsViewModel getVm() {
return mVm;
}
Somewhere in code:
//now I have to do this
binding.vm?.observeOrientation()
?.subscribe()
?.addTo(subscriptions)

Memory leak in Java, but not in Kotlin (of same code base)... why? [duplicate]

This question already has answers here:
Kotlin : safe lambdas (no memory leak)?
(3 answers)
Closed 5 years ago.
I have a piece of simple code below in an activity...
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
}
});
valueAnimator.start();
}
}
If the activity got terminated, there will be memory leak (as proven by Leak Canary).
However, when I covert this code to identical Kotlin code (using shift-alt-command-k), it is as below
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
valueAnimator.repeatCount = ValueAnimator.INFINITE
valueAnimator.addUpdateListener { }
valueAnimator.start()
}
}
Memory leak no longer happen. Why? Is it because the anonymous class object got converted to Lambda?
The difference between these 2 versions is pretty simple.
Java version of the AnimatorUpdateListener contains implicit reference to the outer class (MainActivity in your case). So, if the animation keeps running when the activity is not needed anymore, the listener keeps holding the reference to the activity, preventing it from being garbage-collected.
Kotlin tries to be more clever here. It sees that the lambda which you pass to the ValueAnimator does not reference any objects from the outer scope (i.e. MainActivity), so it creates a single instance of AnimatorUpdateListener which will be reused whenever you [re]start the animation. And this instance does not have any implicit references to the outer scope.
Side note: if you add the reference to some object from outer scope to your lambda, Kotlin will generate the code which creates a new instance of the update listener every time the animation is [re]started, and these instances will be holding the implicit references to MainActivity (required in order to access the object(s) which you decide to use in your lambda).
Another side note: I strongly recommend to read the book called "Kotlin in Action" as it contains lots of useful information on Kotlin in general, and my explanation of how Kotlin compiler make a choice about whether to put the implicit reference to outer scope into the object created after SAM conversion or not comes from this book.
1. Check what's actually going on
I think you'll find the “Show Kotlin Bytecode” view very helpfull in seeing exactly what is going on. See here for the InteliJ shortcut.
(Would have done this for you, but hard without greater context of your application)
2. JVM similarities, but Kotlin explicit differences
But since Kotlin runs on the same JVM as Java (and so uses the same garbage collector as Java) you should expect a similarly safe runtime environment. That being said, when it comes to Lamdas and explicit references, when they're converted. And it can vary in different cases:
Like in Java, what happens in Kotlin varies in different cases.
If the lambda is passed to an inline function and isn’t marked noinline, then the whole thing boils away and no additional classes
or objects are created.
If the lambda doesn’t capture, then it’ll be emitted as a singleton class whose instance is reused again and again (one class+one
object allocation).
If the lambda captures then a new object is created each time the lambda is used.
Source: http://openjdk.java.net/jeps/8158765
3. Summary, and further reading
This answer should explain what your seeing, couldn't have explained it better myself: https://stackoverflow.com/a/42272484/979052
Different question, I know, but the theory behind it is the same - hope that helps
As you already suggested, the argument to addUpdateListener is actually different in both versions.
Let's see an example. I've created a class JavaAbstract with a single abstract method foo:
public interface JavaInterface {
void foo();
}
This is used in JavaInterfaceClient:
public class JavaInterfaceClient {
public void useInterfaceInstance(JavaAbstract inst){
inst.foo();
}
}
Let's see how we can call useInterfaceInstance from Kotlin:
First, with a simple lambda as in your example (SAM Conversion):
JavaInterfaceClient().useInterfaceInstance {}
The resulting bytecode represented in Java:
(new JavaInterfaceClient()).useInterfaceInstance((JavaInterface)null.INSTANCE);
As you can see, very simple, no object instantiations.
Second, with an anonymous instance:
JavaInterfaceClient().useInterfaceInstance(object : JavaInterface {
override fun foo() {
}
})
The resulting bytecode represented in Java:
(new JavaInterfaceClient()).useInterfaceInstance((JavaInterface)(new JavaInterface() {
public void foo() {
}
}));
Here we can observe new object instantiations, which defers from the SAM conversion / lambda approach. You should try the second example in your code.

Mockito avoid passing method arguments when calling Mockit.verify()

I want to test some method, for example:
public class testObj {
..
public void upload(Context context, Data data, Info info, Listener listener, Bla bla, ....) {
...
}
}
now in some cases i just want to know that this method was called, but i do not care about anyy of the arguments passed.
Now calling Mockito.any(Foo.class) is very discouraging, I know i can also use matchers but it's not that great also.
Is there some cleaner way to achive this?
No; verify needs to identify the method you're referring to, which means you'll need to call the correct method signature. Keeping an actual method call will also allow IDEs and automated refactoring tools to search for and modify the calls appropriately.
If you're running your tests from a Java 8 source environment, you can use any() with no argument; Java 8 has improved the ability to infer generic types when given as a parameter.
Though it usually makes more sense just to use matchers and explicit calls, you do have a few similar capabilities:
For stubbing, you can sometimes use a default answer to avoid specifying a lot of redundant calls and method values, but that won't help you with verification.
For verification, you can use MockingDetails.getInvocations() to inspect calls without using the built-in Mockito capabilities.
PowerMockito has private method verification by name, but not the same for public methods.

Rx-java pass by reference or pass by value?

In java methods 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. but in this method i get different result:
I have this method:
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);
}
}
)
}
and i manipulate menu attributes in the flatmap:
menu.config.extensions.get(e.getKey()).config.localPrompt = "";
I call the method in the same class:
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));
}
and finally:
saveSettings(ns, mNumberSettingNew).subscribe();
What i expect is that the mNumberSettingNew.menu.config.extensions.get(e.getKey()).config.prompt is changed but no change is happening after this call and the mNumberSettingNew has no change at all.
Note that i am sure that changing prompt line is done in the debug.
I don't think I could explain Java's parameter semantics any better than (or even half as good as) the link you referenced in your first paragraph so I won't try. The main point is: Everything in Java is passed by value (i. e. copied) but with objects what is copied is not the object itself but the reference to the object. So in other words the reference is passed by value.
So with respect to your particular problem: Yes, if you pass a reference to a mutable object to some rx-java code that reference will point to the same instance of the object. If you mutate the instance then the caller code will also be able to see the changes because they were made on the same instance. That's because rx-java is still only Java and cannot change the language semantics on that level.
Without seeing the whole code I am unsure what could be the problem here... When are you checking whether mNumberSettingsNew actually has the changes you were making in your doOnNext? If you check that immediately after saveSettings(ns, mNumberSettingNew).subscribe(); your uploadAsync may not have returned yet. You could try adding an actual Subscriber in your subscribe and check the result there.
On a more general note, I think you should try to avoid side-effects like this as much as you can when using rx-java. Your case - taking an input object, applying a set of (possibly asynchronous) changes to that object, and waiting for the changed output object - is a bit tricky, but I think it could be done with scan. Maybe something vaguely like this:
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;
}
)
This would take the original Version of the menu, consecutively apply all the changes from added and edited and /emit/ every updated version of menu. So you would not have any side effects but simply subscribe to that observable with a Subscriber<Menu> and then take the last() Menu and that would be the one with all changes applied.
EDIT: Oh, I just saw that there is another method called reduce that does just that: first scan and then last or takeLast.

Categories

Resources