Convert from `ObservableEmitter` to `Observer` in rx-java2 - rx-java2

Is there a easy way to convert from io.reactivex.ObservableEmitter<T>to io.reactivex.Observer<T>? I could not find function to do that in rx-java2 library.
The implementation seems to be trivial:
public static <T> Observer<T> toObserver(ObservableEmitter<T> oe) {
return new Observer<T>() {
#Override
public void onSubscribe(Disposable d) {
oe.setDisposable(d);
}
#Override
public void onNext(T t) {
oe.onNext(t);
}
#Override
public void onError(Throwable e) {
oe.onError(e);
}
#Override
public void onComplete() {
oe.onComplete();
}
};
}
but it feels that it should be part of standard library implementation, as it provides transformation between two core types in rx-java2.
Basically I am trying to migrate following code from rxjava 1 to 2
class X<T, O1, O2> implements Transformer<T, Either<O1, O2>> {
Transformer<T, O1> t1;
Transformer<T, O2> t2;
#Override
public Observable<Either<O1, O2>> call(Observable<T> input) {
return input.flatMap(new Func1<T, Observable<Either<O1, O2>>>() {
#Override
public Observable<Either<O1, O2>> call(final T t) {
return Observable.<Either<O1, O2>>create(new OnSubscribe<Either<O1, O2>>() {
#Override
public void call(final Subscriber<? super Either<O1, O2>> sub) {
t1.call(Observable.just(t)).map(o1 -> Either.<O1, O2>left(o1)).subscribe(sub);
t2.call(Observable.just(t)).map(o2 -> Either.<O1, O2>right(o2)).subscribe(sub);
}
});
}
});
}
}
Notice that OnSubscribe provides Subscriber interface which I can then use to subscribe to two other Observable's, with rxjava 2 conversion is needed.

Looks like you need publish(Function):
(Your code looks convoluted and was violating the protocol in v1 by the way).
ObservableTransformer<T, O1> t1 = ...
ObservableTransformer<T, O2> t2 = ...
ObservableTransformer<T, Either<O1, O2>> combiner = o ->
o.publish(g -> Observable.merge(
t1.apply(g).map(o1 -> Either.<O1, O2>left(o1)),
t2.apply(g).map(o2 -> Either.<O1, O2>right(o2))
));
If you really want to stick to the outer flatMap (in case the inners go async), use merge() instead of create:
return input.flatMap(new Func1<T, Observable<Either<O1, O2>>>() {
#Override
public Observable<Either<O1, O2>> call(final T t) {
Observable<T> just = Observable.just(t);
Observable.merge(
t1.call(just).map(o1 -> Either.<O1, O2>left(o1)),
t2.call(just).map(o2 -> Either.<O1, O2>right(o2))
)
}
});

Related

AAC: How return result (handle click) from ViewModel to activity?

I want to use in my project Android Architecture Components (AAC).
Nice.
Here my activity:
import androidx.appcompat.app.AppCompatActivity;
public class TradersActivity extends AppCompatActivity {
private TradersViewModel tradersViewModel;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tradersViewModel = ViewModelProviders.of(this).get(TradersViewModel.class);
tradersViewModel.getIsEnableSwipeProgress().observe(this, new Observer<Boolean>() {
#Override
public void onChanged(Boolean isEnable) {
// do some work with UI
}
});
}
// button click
public void onClickViewJson(Trader trader) {
tradersViewModel.doClickJsonView(trader);
}
}
Here my ViewModel
public class TradersViewModel extends ViewModel {
private MutableLiveData<Boolean> isEnableSwipeProgress = new MutableLiveData<>();
public void doClickJsonView(Trader trader) {
// DO_SOME_COMPLEX_BUSINESS_LOGIC
}
public MutableLiveData<Boolean> getIsEnableSwipeProgress() {
return isEnableSwipeProgress;
}
}
In the screen I has button. And when click this button I call activity's method - onClickViewJson(Trader trader) .
This method call tradersViewModel.doClickJsonView(trader);
In the viewModel this method do some complex business logic.
After method finish it work I need to return result (json) to the my activity.
How I can do this?
Remember that in MVVM, ViewModels have not idea about your view.
Your ViewModel should expose variables so your views can observe and react over them.
private MutableLiveData<Boolean> isEnableSwipeProgress = new MutableLiveData<>();
private MutableLiveData<JSONDto> jsonLiveData = new MutableLiveData<>();
public void doClickJsonView(Trader trader) {
// DO_SOME_COMPLEX_BUSINESS_LOGIC
jsonLiveData.postValue(/* the json you obtain after your logic finish */ )
}
public MutableLiveData<Boolean> getIsEnableSwipeProgress() {
return isEnableSwipeProgress;
}
public LiveData<JSONDto> getJsonDto() {
return this.jsonLiveData;
}
And in your view, you react over your jsonDto changes:
tradersViewModel.getJsonDto().observe(this, new Observer<JSONDto>() {
#Override
public void onChanged(JSONDto json) {
if (json != null) {
// Do what you need here.
}
}
});

RxJava Single.concat

I have the following code:
model.getCategories()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<List<Category>>()
{
#Override
public void call(final List<Category> categories)
{
model.getUnits()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<List<Unit>>()
{
#Override
public void call(List<Unit> units)
{
view.showAddProductDialog(units, categories);
}
});
}
});
I have this ugly nesting. How can I fix it.
I tried something like this:
Single.concat(model.getCategories(), model.getUnits())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<List<? extends Object>>()
{
#Override
public void call(List<? extends Object> objects)
{
// do something
}
});
But the problem is that I cannot determinate whether it is List<Category> or List<Unit> comes.
Is there a way to use concat and detect what kind of stream comes (List<Category> or List<Unit> or something else) ?
Also I need to detect that all observers are completed to perform another action.
Thanks in advice.
Use Single.zip():
Single.zip(
getCategories().subscribeOn(Schedulers.io()),
getUnits().subscribeOn(Schedulers.io()),
(a, b) -> Pair.of(a, b)
)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
pair -> view.showAddProductDialog(pair.first, pair.second),
error -> showError(error.toString())
)
where Pair can be any tuple implementation, i.e., this.

When is it necessary to check if a subscriber is subscribed prior to calling onNext() and onError()?

Consider the following example, it creates an Observable that wraps another API that produces Widgets
public Observable<Widget> createWidgetObservable() {
return Observable.create(new Observable.OnSubscribe<Widget>() {
#Override
public void call(final Subscriber<? super Widget> subscriber) {
WidgetCreator widgetCreator = new WidgetCreator();
widgetCreator.setWidgetCreatorObserver(new WidgetCreator.WidgetCreatorObserver() {
#Override
public void onWidgetCreated(Widget widget) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(widget);
}
}
#Override
public void onWidgetError(Throwable e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
});
}
});
}
Are the subscriber.isUnsubscribed() checks necessary prior to calling subscriber.onNext() and subscriber.onError()?
If so, are the checks always necessary or does it depend on the composition / subscriber that's using the observable?
Is it best practice to include the checks?
You can use them to narrow the window between an emission and an unsubscription but if you don't have loops, it is unnecessary most of the time. The more important thing is that if an unsubscription happen, you'd have to "unset" the WidgetCreatorObserver otherwise it will keep receiving and dropping data and keeping alive every reference it may hold.
WidgetCreator widgetCreator = new WidgetCreator();
WidgetCreator.WidgetCreatorObserver wo = new WidgetCreator.WidgetCreatorObserver() {
#Override
public void onWidgetCreated(Widget widget) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(widget);
}
}
#Override
public void onWidgetError(Throwable e) {
if (!subscriber.isUnsubscribed()) {
subscriber.onError(e);
}
}
}
widgetCreator.setWidgetCreatorObserver(wo);
wo.add(Subscriptions.create(() -> widgetCreator.removeWidgetCreatorObserver(wo)));

Average in RxJava

I am trying to make a system resource monitor using Rx. I use a thread for observable which returns the CPU Usage every 1000 milliseconds. Now I want my subscriber to find the average of the CPU usage every 10 seconds.
public class seperate {
private ScheduledThreadPoolExecutor executorPool;
public void test()
{
Observable<Double> myObservable = Observable.create(
new Observable.OnSubscribe<Double>() {
#Override
public void call(Subscriber<? super Double> sub) {
executorPool = new ScheduledThreadPoolExecutor(9);
int timeout1 = 10;
TimerTask timeoutTimertask1=new MyTimerTasks(sub);
executorPool.scheduleAtFixedRate(timeoutTimertask1,timeout1, timeout1,
TimeUnit.MILLISECONDS);
// This returns the cpu usage every 10ms.
}
}
);
Subscriber<Double> mySubscriber = new Subscriber<Double>() {
#Override
public void onNext(Double s) { System.out.println(s); }
#Override
public void onCompleted() { }
#Override
public void onError(Throwable e) { }
};
myObservable.subscribe(mySubscriber);
}
}
You can use buffer or window to divide source emission into groups of items, then calculate average on each group.
Avarage is a part of rxjava-math library.
Moreover you can simplify your code using interval.
Below is example using window and interval:
Observable myObservable = Observable.interval(10, TimeUnit.MILLISECONDS)
.map(new Func1<Long, Double>() {
#Override
public Double call(Long aLong) {
Double d = 100.;//calculate CPU usage
return d;
}
})
.window(10, TimeUnit.SECONDS)
.flatMap(new Func1<Observable<Double>, Observable<Double>>() {
#Override
public Observable<Double> call(Observable<Double> windowObservable) {
return MathObservable.averageDouble(windowObservable);
}
});
Use MathObservable like so:
MathObservable.averageLong(longsObservable).subscribe(average -> Timber.d("average:%d", average));
More info can be found here:
https://github.com/ReactiveX/RxJava/wiki/Mathematical-and-Aggregate-Operators
Source Code:
https://github.com/ReactiveX/RxJavaMath

GEF + EMF: Why doesn't my editor remove the Figure for a removed object when refreshChildren() is called?

I have implemented a GEF editor for a graph-like EMF model, with a remove command for a certain type of node in the graph. I think I've done all the necessary steps in order to make this set up work (vainolo's blog has been a great help).
However, when I'm deleting a model element, the view doesn't get refreshed, i.e., the figure for the model element isn't removed from the editor view, and I have no idea why. I'd be extremely grateful if somebody could have a look at my sources and point me to any problems (and possibly solutions :)). Many thanks in advance!
Below are what I think are the important classes for this issue. Please do let me know should I add further code/edit the code, etc. (I've left out code that I thought doesn't help, e.g., getters and setters, class variables). Thanks!
DiagramEditPart
public class DiagramEditPart extends AbstractGraphicalEditPart {
public DiagramEditPart(Diagram model) {
this.setModel(model);
adapter = new DiagramAdapter();
}
#Override protected IFigure createFigure() {
Figure figure = new FreeformLayer();
return figure;
}
#Override protected void createEditPolicies() {
installEditPolicy(EditPolicy.LAYOUT_ROLE, new DiagramXYLayoutPolicy());
}
#Override protected List<EObject> getModelChildren() {
List<EObject> allModelObjects = new ArrayList<EObject>();
if (((Diagram) getModel()).getMyNodes() != null)
allModelObjects.addAll(((Diagram) getModel()).getMyNodes());
return allModelObjects;
}
#Override public void activate() {
if(!isActive()) {
((Diagram) getModel()).eAdapters().add(adapter);
}
super.activate();
}
#Override public void deactivate() {
if(isActive()) {
((Diagram) getModel()).eAdapters().remove(adapter);
}
super.deactivate();
}
public class DiagramAdapter implements Adapter {
#Override public void notifyChanged(Notification notification) {
switch (notification.getEventType()) {
case Notification.REMOVE: refreshChildren();
break;
default:
break;
}
}
#Override public Notifier getTarget() {
return (Diagram) getModel();
}
#Override public void setTarget(Notifier newTarget) {
// Do nothing.
}
#Override public boolean isAdapterForType(Object type) {
return type.equals(Diagram.class);
}
}
}
MyNodeEditPart
public class MyNodeEditPart extends AbstractGraphicalEditPart {
public MyNodeEditPart(MyNode model) {
this.setModel(model);
adapter = new MyNodeAdapter();
}
#Override protected IFigure createFigure() {
return new MyNodeFigure();
}
#Override protected void createEditPolicies() {
installEditPolicy(EditPolicy.COMPONENT_ROLE, new MyNodeComponentEditPolicy());
}
#Override protected void refreshVisuals() {
MyNodeFigure figure = (MyNodeFigure) getFigure();
DiagramEditPart parent = (DiagramEditPart) getParent();
Dimension labelSize = figure.getLabel().getPreferredSize();
Rectangle layout = new Rectangle((getParent().getChildren().indexOf(this) * 50),
(getParent().getChildren().indexOf(this) * 50), (labelSize.width + 20),
(labelSize.height + 20));
parent.setLayoutConstraint(this, figure, layout);
}
public List<Edge> getModelSourceConnections() {
if ((MyNode) getModel() != null && ((MyNode) getModel()).getDiagram() != null) {
ArrayList<Edge> sourceConnections = new ArrayList<Edge>();
for (Edge edge : ((MyNode) getModel()).getDiagram().getOutEdges(((MyNode) getModel()).getId())) {
sourceConnections.add(edge);
}
return sourceConnections;
}
return null;
}
// + the same method for targetconnections
#Override public void activate() {
if (!isActive()) {
((MyNode) getModel()).eAdapters().add(adapter);
}
super.activate();
}
#Override public void deactivate() {
if (isActive()) {
((MyNode) getModel()).eAdapters().remove(adapter);
}
super.deactivate();
}
public class MyNodeAdapter implements Adapter {
#Override
public void notifyChanged(Notification notification) {
refreshVisuals();
}
#Override
public Notifier getTarget() {
return (MyNode) getModel();
}
#Override
public void setTarget(Notifier newTarget) {
// Do nothing
}
#Override
public boolean isAdapterForType(Object type) {
return type.equals(MyNode.class);
}
}
}
MyNodeComponentEditPolicy
public class MyNodeComponentEditPolicy extends ComponentEditPolicy {
#Override
protected Command createDeleteCommand(GroupRequest deleteRequest) {
DeleteMyNodeCommand nodeDeleteCommand = new DeleteMyNodeCommand((MyNode) getHost().getModel());
return nodeDeleteCommand;
}
}
DeleteMyNodeCommand
public class DeleteMyNodeCommand extends Command {
public DeleteMyNodeCommand(MyNode model) {
this.node = model;
this.graph = node.getDiagram();
}
#Override public void execute() {
getMyNode().setDiagram(null);
System.out.println("Is the model still present in the graph? " + getGraph().getMyNodes().contains(getMyNode()));
// Returns false, i.e., graph doesn't contain model object at this point!
}
#Override public void undo() {
getMyNode().setDiagram(getGraph());
}
}
EDIT
Re execc's comment: Yes, refreshChildren() is being called. I've tested this by overriding it and adding a simple System.err line, which is being displayed on the console on deletion of a node:
#Override
public void refreshChildren() {
super.refreshChildren();
System.err.println("refreshChildren() IS being called!");
}
EDIT 2
The funny (well...) thing is, when I close the editor and persist the model, then re-open the same file, the node isn't painted anymore, and is not present in the model. But what does this mean? Am I working on a stale model? Or is refreshing/getting the model children not working properly?
EDIT 3
I've just found a peculiar thing, which might explain the isues I have? In the getModelChildren() method I call allModelObjects.addAll(((Diagram) getModel()).getMyNodes());, and getMyNodes() returns an unmodifiable EList. I found out when I tried to do something along the lines of ((Diagram) getModel()).getMyNodes().remove(getMyNode()) in the delete command, and it threw an UnsupportedOperationException... Hm.
EDIT 4
Er, somebody kill me please?
I've double-checked whether I'm handling the same Diagram object at all times, and while doing this I stumbled across a very embarassing thing:
The getModelChildren() method in DiagramEditPart in the last version read approx. like this:
#Override protected List<EObject> getModelChildren() {
List<EObject> allModelObjects = new ArrayList<EObject>();
EList<MyNode> nodes = ((Diagram) getModel()).getMyNodes();
for (MyNode node : nodes) {
if (node.getDiagram() != null); // ### D'Uh! ###
allModelObjects.add(node);
}
return allModelObjects;
}
I'd like to apologize for stealing everyone's time! Your suggestions were very helpful, and indeed helped my to finally track down the bug!
I've also learned a number of lessons, amongst them: Always paste the original code, over-simplifaction may cloak your bugs! And I've learned a lot about EMF, Adapter, and GEF. Still:
There is one semi-colon too many in line 5 of the following part of the code, namely after the if statement: if (node.getDiagram() != null);:
1 #Override protected List<EObject> getModelChildren() {
2 List<EObject> allModelObjects = new ArrayList<EObject>();
3 EList<MyNode> nodes = ((Diagram) getModel()).getMyNodes();
4 for (MyNode node : nodes) {
5 if (node.getDiagram() != null);
6 allModelObjects.add(node);
7 }
8 return allModelObjects;
9 }