What I want to do is to create a simple in-memory cache just to try Observables out. However I got stuck because I don't understand how to create an observable. This is the code I have gotten so far:
public class MovieCache {
MovieWrapper movieWrapper;
public Observable<MovieWrapper> getMovies() {
//How to create and return an Observable<MovieWrapper> here?
}
public void setCache(MovieWrapper wrapper) {
movieWrapper = wrapper;
}
public void clearCache() {
movieWrapper = null;
}
}
In the getMovies() method I want to create an Observable and return my local field movieWrapper to the subscriber. How can I do this? I tried with using new Observable.just(movieWrapper) but it results in a null exception.
Take a look at this tutorial as it does exactly what you are looking for. Basically you use defer() to make sure you always get the latest version of your cached object:
public class MovieCache {
MovieWrapper movieWrapper;
public Observable<MovieWrapper> getMovies() {
return Observable.defer(new Func0<Observable<MovieWrapper>>() {
#Override
public Observable<MovieWrapper> call() {
return Observable.just(movieWrapper);
}
});
}
public void setCache(MovieWrapper wrapper) {
movieWrapper = wrapper;
}
public void clearCache() {
movieWrapper = null;
}
}
defer() makes sure that you will get the object upon subscription to the Observable not on creation.
Note however that, according to the author of the post:
The only downside to defer() is that it creates a new Observable each
time you get a subscriber. create() can use the same function for each
subscriber, so it's more efficient. As always, measure performance and
optimize if necessary.
As already said, accepted answer has downside
it creates a new Observable each time you get a subscriber
But it is not the only one.
Consumer won't receive any value if he calls getMovies().subscribe(...) before setCache(...) is called.
Consumer should resubscribe if he want to receive any updates (let's say setCache() can be called multiple times.
Of course all of them can be irrelevant in your scenario. I just want to show you another way (I'm sure there are many more).
You can use BehaviorSubject in order to eliminate all these disadvantages.
public class MovieCache {
private BehaviorSubject<MovieWrapper> mMovieCache = BehaviorSubject.create();
public void setCache(MovieWrapper wrapper) {
mMovieCache.onNext(wrapper);
}
public Observable<MovieWrapper> getMovieObservable() {
//use this if consumer want to receive all updates
return mMovieCache.asObservable();
}
public MovieWrapper getMovie() {
//use this if consumer want to get only current value
//and not interested in updates
return mMovieCache.getValue();
}
public void clearCache() {
//CAUTION consumer should be ready to receive null value
mMovieCache.onNext(null);
//another way is to call mMovieCache.onCompleted();
//in this case consumer should be ready to resubcribe
}
public static class MovieWrapper {}
}
Take a look at BehaviorSubject marble diagram.
Related
I am new with tests.
I have something like next code and wish to cover it with unitTests using the Mockito:
public void doSomeJob(){
//some code before
getMvpView().execute(getObservable());
//some code after
}
private Observable<Boolean> getObservable(){
return Observable.create(new ObservableOnSubscribe<Boolean>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Boolean> e) throws Exception {
Thread.sleep(5000);
e.onNext(true);
e.onComplete();
}
});
}
so questions:
how correct write test for getMvpView().execute(getObservable()); using Mokito?
how can i verify result of getObservable()?
If your private method is not a part of the interface, i.e. cannot be reached from outside the class, it's not something you should test (presumably it's not, since it's private). Mockito in turn doesn't provide mocking of private methods. Thereby you either need to change your interface (make this data available outside) or leave it without testing.
What you should test is the effect of calling the public methods of your class under test. If you do so you will be able to freely refactor the implementation details later, and your tests will still verify that your class works as expected.
I suppose that your code is part of a presenter implementation and the getMvpView() method returns a view interface:
public class MvpPresenterImpl {
private MvpView view;
public void doSomeJob(){
//some code before
getMvpView().execute(getObservable());
//some code after
}
public void attachView(MvpView view) {
this.view = view;
}
private MvpView getMvpView() {
return view;
}
private Observable<Boolean> getObservable(){
return Observable.create(new ObservableOnSubscribe<Boolean>() {
#Override
public void subscribe(#NonNull ObservableEmitter<Boolean> e) throws Exception {
Thread.sleep(5000);
e.onNext(true);
e.onComplete();
}
});
}
}
You can test the effect of doSomeJob() like so:
public class MvpPresenterImplTest {
private MvpPresenterImpl presenter;
private MvpView mockView;
#Before
public void setUp() throws Exception {
// Create a mock view instance so that we can verify method calls on it
mockView = mock(MvpView.class);
// Create our object under test, and set it up with the mock view
presenter = new MvpPresenterImpl();
presenter.attachView(mockView);
}
#Test
public void doSomeJob_callsExecuteOnViewWithCorrectObserver() throws Exception {
// What we want to test is the effect of invoking a public method.
presenter.doSomeJob();
// Verify that the execute method has been called by your class
// under test, and save the parameter for later.
ArgumentCaptor<Observable<Boolean>> paramCaptor =
ArgumentCaptor.<Observable<Boolean>>forClass((Class)Observable.class);
verify(mockView).execute(paramCaptor.capture());
// Get the actual observable that the execute method was called with.
Observable<Boolean> param = paramCaptor.getValue();
// Get a test observer so that we can check what our Observable emits
// (TestObserver is a built-in feature of RxJava, not Mockito.)
TestObserver<Boolean> test = param.test();
// Assert that the Observable behaves as expected
test.assertComplete();
test.assertResult(true);
}
}
I'm using MVVM on android application and i want to manage requests and rxJava on device rotation, how can i disable request after rotation device and countinue from last request?
this is my simple code to know how can i doing that, but i can't find any document and sample code about it
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_register);
...
Observer<String> myObserver = new Observer<String>() {
#Override
public void onError(Throwable e) {
// Called when the observable encounters an error
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String s) {
// Called each time the observable emits data
Log.e("MY OBSERVER", s);
}
};
Observable.just("Hello").subscribe(myObserver);
}
I'm using latest version of rxJava
Handling rotation is a cool challenge in Android. There're a few ways to do that.
1- Services: You can use a service and handle your network requests or other background operations in service. Also with Services, you'll seperate your business logic from ui.
2- Worker Fragment: Worker fragment is a fragment instance without a layout. You should set your worker fragment's retainInstanceState to true. So you'll save your fragment from orientation change and will not lose your background operations.
Why Worker Fragment? If you set retainInstanceState true to a fragment with layout, you'll leak views.
If you're using MVVM you can implement ViewModel as a Worker Fragment which as setRetainInstanceState = true
3- Global Singleton Data Source: You can create a global singleton data source class which handles your operations in an independent scope from Activity / Fragment lifecycle in your application.
4- Loaders: Loaders can recover state from orientation changes. You handle your operations with loaders but they are designed to load data from disk and are not well suited for long-running network requests.
Extra: You can use Path's Priority Job Queue to persist your jobs:
https://github.com/path/android-priority-jobqueue
Edit: You can check my repo for handling device rotation without using Google's new architecture components. (As an example of Worker Fragment which i pointed in my answer.)
https://github.com/savepopulation/bulk-action
You have the following options:
Use some global Singleton, or your Application class, that holds your logic, not within your Activity's lifecycle
Use a Service that runs next to your activity/application
Use a Loader
Global state is often bad and makes your code hard to test / debug. Services tend to be overkill.
For your use case of device rotation and continuing where one left off you'd usually use a Loader, which keeps running on rotation and only gets destroyed once you leave the activity.
I also recently wrote an article about one possible solution to use Loaders together with RxJava to keep state during orientation changes.
You can take advantage of Fragment#setRetainInstance(true). With that flag set, fragment is not destroyed after device rotation and can be used as an object container. Please look at this sample which also stores Observable - https://github.com/krpiotrek/RetainFragmentSample
you need to override
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
When device is rotated store data in bundle then inside on create check
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null){
//saved instance is null
}else{
//get your stored values here
counter = savedInstanceState.getInt("value",0); //here zero is the default value
}
}
How I'm doing this is to have a singleton class (or any long living Object as explained by savepopulation earlier, but - the trick is to store the loaded data in a BehaviorSubject, and subscribe to that subject in the Activity instead of the original network request.
This way:
public class MyNetworkSingleton {
// This static service survives orientation changes
public static MyNetworkSingleton INSTANCE = new MyNetworkSingleton();
private final BehaviorSubject<String> dataSubject = BehaviorSubject.create();
public Observable<String> getData() {
if (!dataSubject.hasValue()) {
refreshData(); // No data is loaded yet, load initial data from network
}
return dataSubject;
}
public void refreshData() {
someDataSourceCall().subscribe(new Observer<String>() {
#Override
public void onError(Throwable e) {
// Remember, this point also needs error handling of some form,
// e.g. propagating the error to the UI as a Toast
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String data) {
dataSubject.onNext(data); // this refreshes the internally stored data
}
});
}
private Observable<String> someDataSourceCall() {
return // some network request here etc. where you get your data from
}
}
and then:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Observer<String> myObserver = new Observer<String>() {
#Override
public void onError(Throwable e) {
// Called when the observable encounters an error
}
#Override
public void onComplete() {
}
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(String s) {
// Called each time the observable emits data
Log.e("MY OBSERVER", s);
}
};
MyNetworkSingleton.INSTANCE.getData().subscribe(myObserver);
myRefreshButton.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
// refresh data from network only when button is pressed
MyNetworkSingleton.INSTANCE.refreshData();
}
});
}
This way only first time you need the data from network it will be loaded, or when the user clicks a refresh button (myRefreshButton).
Im exactly having this behavior
Subscriber OnComplete called twice
(which is is anticipated as per http://reactivex.io/documentation/subject.html)
But in my scenario : it goes something like this :
I have a AudioRecordingService which displays a notification, in which I have options for the user to save or delete the on going recording, which is working perfectly. But I'm trying to get into using RxAndroid, my notification's save button would trigger..
RxEventBus.getInstance().postEvent(new RxEvents(RxEventsEnum.AUDIO_STOP_AND_SAVE));
which triggers
bindUntilActivitySpecificEvent(RxEventBus.getInstance().forEventType(RxEvents.class),ActivityEvent.DESTROY).subscribeOn(
AndroidSchedulers.mainThread()).subscribe(new Action1<RxEvents>() {
#Override public void call(RxEvents rxEvents) {
onEvent(rxEvents);
}
});
and in my onEvent(rxEvent) based on the rxEvents object's data I appropriately save and store recording. The first time I try this, it works fine, but the subsequent times, the
#Override public void call(RxEvents rxEvents) {
onEvent(rxEvents);
}
is being called multiple times, like for example the second time I post an event, this callback is called twice, the third time thrice and so on... (which is actually what PublishSubject does). I don't want this behavior, I want Rx to be a able to post events and receive only the latest event that was posted and nothing else.
Here is my other relevant code
protected final <T> Observable<T> bindUntilActivitySpecificEvent(Observable<T> observable,
ActivityEvent event) {
return observable.compose(RxLifecycle.<T, ActivityEvent>bindUntilEvent(lifecycle(), event))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
and my run of the mill RxEventBus class :
public class RxEventBus {
private static final RxEventBus INSTANCE = new RxEventBus();
public static RxEventBus getInstance() {
return INSTANCE;
}
private RxEventBus() {
}
private final Subject<Object, Object> mBus = new SerializedSubject<>(PublishSubject.create());
public void postEvent(Object event) {
mBus.onNext(event);
}
public <T> Observable<T> forEventType(Class<T> eventType) {
return mBus.ofType(eventType).observeOn(AndroidSchedulers.mainThread());
}
}
What is the best approach using RxAndroid ? Please note that I am looking for RxAndroid solution only.
You are creating a new observable every time you trigger an event in
RxEventBus.getInstance().forEventType(RxEvents.class)
You need to cache the observables you create for each event type.
I'm start learning RxJava and I like it so far. I have a fragment that communicate with an activity on button click (to replace the current fragment with a new fragment). Google recommends interface for fragments to communicate up to the activity but it's too verbose, I tried to use broadcast receiver which works generally but it had drawbacks.
Since I'm learning RxJava I wonder if it's a good option to communicate from fragments to activities (or fragment to fragment)?. If so, whats the best way to use RxJava for this type of communication?. Do I need to make event bus like this one and if that's the case should I make a single instance of the bus and use it globally (with subjects)?
Yes and it's pretty amazing after you learn how to do it. Consider the following singleton class:
public class UsernameModel {
private static UsernameModel instance;
private PublishSubject<String> subject = PublishSubject.create();
public static UsernameModel instanceOf() {
if (instance == null) {
instance = new UsernameModel();
}
return instance;
}
/**
* Pass a String down to event listeners.
*/
public void setString(String string) {
subject.onNext(string);
}
/**
* Subscribe to this Observable. On event, do something e.g. replace a fragment
*/
public Observable<String> getStringObservable() {
return subject;
}
}
In your Activity be ready to receive events (e.g. have it in the onCreate):
UsernameModel usernameModel = UsernameModel.instanceOf();
//be sure to unsubscribe somewhere when activity is "dying" e.g. onDestroy
subscription = usernameModel.getStringObservable()
.subscribe(s -> {
// Do on new string event e.g. replace fragment here
}, throwable -> {
// Normally no error will happen here based on this example.
});
In you Fragment pass down the event when it occurs:
UsernameModel.instanceOf().setString("Nick");
Your activity then will do something.
Tip 1: Change the String with any object type you like.
Tip 2: It works also great if you have Dependency injection.
Update:
I wrote a more lengthy article
Currently I think my preferred approach to this question is this to:
1.) Instead of one global bus that handles everything throughout the app (and consequently gets quite unwieldy) use "local" buses for clearly defined purposes and only plug them in where you need them.
For example you might have:
One bus for sending data between your Activitys and your ApiService.
One bus for communicating between several Fragments in an Activity.
One bus that sends the currently selected app theme color to all Activitys so that they can tint all icons accordingly.
2.) Use Dagger (or maybe AndroidAnnotations if you prefer that) to make the wiring-everything-together a bit less painful (and to also avoid lots of static instances). This also makes it easier to, e. g. have a single component that deals only with storing and reading the login status in the SharedPreferences - this component could then also be wired directly to your ApiService to provide the session token for all requests.
3.) Feel free to use Subjects internally but "cast" them to Observable before handing them out to the public by calling return subject.asObservable(). This prevents other classes from pushing values into the Subject where they shouldn't be allowed to.
Define events
public class Trigger {
public Trigger() {
}
public static class Increment {
}
public static class Decrement {
}
public static class Reset {
}
}
Event controller
public class RxTrigger {
private PublishSubject<Object> mRxTrigger = PublishSubject.create();
public RxTrigger() {
// required
}
public void send(Object o) {
mRxTrigger.onNext(o);
}
public Observable<Object> toObservable() {
return mRxTrigger;
}
// check for available events
public boolean hasObservers() {
return mRxTrigger.hasObservers();
}
}
Application.class
public class App extends Application {
private RxTrigger rxTrigger;
public App getApp() {
return (App) getApplicationContext();
}
#Override
public void onCreate() {
super.onCreate();
rxTrigger = new RxTrigger();
}
public RxTrigger reactiveTrigger() {
return rxTrigger;
}
}
Register event listener wherever required
MyApplication mApp = (App) getApplicationContext();
mApp
.reactiveTrigger() // singleton object of trigger
.toObservable()
.subscribeOn(Schedulers.io()) // push to io thread
.observeOn(AndroidSchedulers.mainThread()) // listen calls on main thread
.subscribe(object -> { //receive events here
if (object instanceof Trigger.Increment) {
fabCounter.setText(String.valueOf(Integer.parseInt(fabCounter.getText().toString()) + 1));
} else if (object instanceof Trigger.Decrement) {
if (Integer.parseInt(fabCounter.getText().toString()) != 0)
fabCounter.setText(String.valueOf(Integer.parseInt(fabCounter.getText().toString()) - 1));
} else if (object instanceof Trigger.Reset) {
fabCounter.setText("0");
}
});
Send/Fire event
MyApplication mApp = (App) getApplicationContext();
//increment
mApp
.reactiveTrigger()
.send(new Trigger.Increment());
//decrement
mApp
.reactiveTrigger()
.send(new Trigger.Decrement());
Full implementation for above library with example -> RxTrigger
I'm new in reactive programming. So I have problem when create a stream from an Event, like onClick, ontouch...
Can anyone help me solve this problem.
Thanks.
You would do something like this:
Observable<View> clickEventObservable = Observable.create(new Observable.OnSubscribe<View>() {
#Override
public void call(final Subscriber<? super View> subscriber) {
viewIWantToMonitorForClickEvents.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (subscriber.isUnsubscribed()) return;
subscriber.onNext(v);
}
});
}
});
// You can then apply all sorts of operation here
Subscription subscription = clickEventObservable.flatMap(/* */);
// Unsubscribe when you're done with it
subscription.unsubscribe();
Since you're using Android then you may already include the contrib rxjava-android dependency now known as ioreactivex:rxandroid.
They already have a class to facilitate this. The method is ViewObservable.clicks. You can use it like so.
Observable<View> buttonObservable = ViewObservable.clicks(initiateButton, false);
buttonObservable.subscribe(new Action1<View>() {
#Override
public void call(View button) {
// do what you need here
}
});
Edit: Since version 1.x, ViewObservable and many helper classes are removed from RxAndroid. You will need RxBinding library instead.
Observable<Void> buttonObservable = RxView.clicks(initiateButton);
buttonObservable.subscribe(new Action1<Void>() {
#Override
public void call(Void x) {
// do what you need here
}
});
For Android development, have a look at Jake Wharton's RxBindings. For example, it allows you to create an observable and subscribe to click events with:
RxView.clicks(myButton)
.subscribe(new Action1<Void>() {
#Override
public void call(Void aVoid) {
/* do something */
}
});
or, even better, with lambda expressions (using either Kotlin, Java 8 or Retrolambda):
RxView.clicks(myButton)
.subscribe(aVoid -> /* do something */);
If you're using Kotlin, it's worth noting that RxBindings also provides Kotlin extension functions that allow you to apply each binding function directly on the target type.
You could use a Subject.
A Subject is a sort of bridge or proxy that acts both as an Subscriber and as an Observable. Because it is a Subscriber, it can subscribe to one or more Observables, and because it is an Observable, it can pass through the items it observes by reemitting them, and it can also emit new items.
public class Events {
public static PublishSubject <Object> myEvent = PublishSubject.create ();
}
When you want to publish something
Events.myEvent.onNext(myObject);
When you want to receive an event
Events.myEvent.subscribe (...);
Edit
**Using Architecture Components LiveData is better because it handles the lifecycle of and activity or fragment and you don't have to worried about unsubscribe from events because it observe the ui components lifecycle.
MutableLiveData<Object> event = new MutableLiveData<>();
when you want to publish something
event.postValue(myObject);
When you want to receive and event
event.observe(lifeCycleOwner, (myObject)->...);
Using RxJava 2:
return Observable.create(new ObservableOnSubscribe<View>() {
#Override
public void subscribe(ObservableEmitter<View> e) throws Exception {
clickView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
e.setCancellable(new Cancellable() {
#Override
public void cancel() throws Exception {
view.setOnClickListener(null);
}
});
e.onNext(view); // Or whatever type you're observing
}
});
}
});
Looks much nicer using lambdas:
return Observable.create(new ObservableOnSubscribe<View>() {
#Override
public void subscribe(ObservableEmitter<View> e) throws Exception {
keypad.setOnClickListener(view -> {
e.setCancellable(() -> view.setOnClickListener(null));
e.onNext(view);
});
}
});
Or just use RxBinding as stated by others.
My solution above is a pretty general pattern for wrapping listeners into an Observable though.
You can do this easily with Kotlin using extension functions. For example you write an extension function like this:
fun View.observableClickListener(): Observable<View> {
val publishSubject: PublishSubject<View> = PublishSubject.create()
this.setOnClickListener { v -> publishSubject.onNext(v) }
return publishSubject
}
And you would use this extension like this:
viewIWantToObserveClicks.observableClickListener().subscribe()