LiveData in Background Threads or non-UI components - android

Dears. I used to develop Android apps using MVP pattern and now I'm trying the MVVM with Architecture components like DataBind and LiveData.
I wrote my Repository class that provides a LiveData:
LiveData<MyEntity> getById(long id);
For Activity/Fragments I observe the LiveData exposed by ViewModel (that uses my Repository) and everything works fine.
The problem is I have to schedule an Alarm to display a Notification with a text related to MyEntity, so I created an Intent containing my MyEntityId as an Extra.
When the AlarmManager calls my BroadcastReceiver, I need to use the Repository to get MyEntity. The point is how to "Observe" the LiveData inside a non-UI component.
Also, I can start an IntentService (background thread) to avoid accessing the Repository in the Main Thread, and use something like "blockingNext" from RxJava, but I still could not figure a way to wait for LiveData.
What is the correct way of doing this? Note that my Repository may not be implemented using Room, due to legacy issues.
Thanks
The only solution I figured so far was have methods like this in the Repository:
LiveData<MyEntity> getByIdLive(long id);
MyEntity getById(long id);
But this does not look good for me.
So I'd like to ask how is the correct way of implement this.
Best Regards

It's better to avoid such things, but if you really need it and really know what you're doing you can try the following code:
public static <T> void observeOnce(final LiveData<T> liveData, final Observer<T> observer) {
liveData.observeForever(new Observer<T>() {
#Override
public void onChanged(T t) {
liveData.removeObserver(this);
observer.onChanged(t);
}
});
}
#WorkerThread
public static <T> T waitSync(final LiveData<T> liveData) {
final Object lock = new Object();
final Object[] result = new Object[1];
final boolean[] resultReady = new boolean[] {false};
(new Handler(Looper.getMainLooper())).post(new Runnable() {
#Override
public void run() {
observeOnce(liveData, new Observer<T>() {
#Override
public void onChanged(T t) {
synchronized (lock) {
result[0] = t;
resultReady[0] = true;
lock.notify();
}
}
});
}
});
synchronized (lock) {
try {
while (!resultReady[0]) {
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
return (T) result[0];
}

You can only observe liveData in UI components like Activity/Fragment.
For your scenario, you can create an observer class which can be observed in non-UI classes as well or you can use EventBus.
to read about observer: https://developer.android.com/reference/java/util/Observer
about EventBus: https://github.com/greenrobot/EventBus

Related

Post multiple MutableLiveData have no order

I'm using multiple MutableLiveData on an MVVM architecture.
on the ViewModel, I post the objects but the fragment is not resumed.
when the fragment has resumed the observers get the MutableLiveData but not in the order I post them.
How can I force an order of getting the MutableLiveData?
ViewModel:
void foo(){
first_MutableLiveData.post(newData)
second_MutableLiveData.post(newData)
}
fragment:
initView(){
first_MutableLiveData.observe(this,()->{
"getting called second"})
second_MutableLiveData.observe(this,()->{
"getting called first"})
}
You can't force what you want. As you can see from the code they are posting the result to the MainThread by calling:
ArchTaskExecutor.getInstance()
So now one would bother to support the syncronization between two different LiveData objects. It is your job do do so. It is a corner case.
Just use setValue, instead of postValue directly on the MainThread. Here is an example.
public class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
#Override
public void execute(Runnable runnable) {
handler.post(runnable);
}
}
public class YourClass {
MutableLiveData first_MutableLiveData = new MutableLiveData<Data>();
MutableLiveData second_MutableLiveData = new MutableLiveData<Data>();
private final Executor executor;
public YourClass(Executor executor) {
this.executor = executor;
}
void foo(){
executor.execute(new Runnable(){
#Override
public void run() {
first_MutableLiveData.setValue(newData);
second_MutableLiveData.setValue(newData);
}
});
}
}
So apparently when I changed the observer's order on the fragment they arrived in the order I needed them to be. Thanks everyone for the quick response!

Clean Architecture, UseCases and Entities

Okay, so I just started a new Android project and wanted to try implementing the Clean Architecture by Uncle Bob. I have a nice beginning using RxJava and stuff from GitHub samples & boilerplates and Fernando Cerjas' blog (like this article), but still have some questions on how to implement some UseCases.
TL;DR
Should an Entity have fields that are another Entity (in my example, User having a List<Messages> field)?
Or should the Presenter combine UseCases to build a ViewModel mapped on multiple Entities (then how to you code the mapper?)?
Or should the Presenter have a ViewModel associated to each UseCase/Entity, and create some kind of "wait for all data to onNext" to call the view.show() for each ViewModel?
Basically, should UseCases only return Entities? Can an Entity be composed of other entities (as in a field of the class)? Are Entities only dumb datamodels POJOs? How to you represent 'join SQL' queries?
As an example, let's take a simple users/messages app.
I want to implement two views: UserList and UserDetails:
UserList displays a list of Users
UserDetails displays a user's information and its latest messages.
UserList is pretty straightforward, and I can see how to code the associated UseCase and layers (code below).
My problem is with the UserDetails screen.
How should I code my GetUserInfoUseCase if I want all the data to be passed at the view at the same time (like building a ViewModel composed of a User class, with a field List)? What should be the return value of the GetUserInfoUseCase?
Should I code a Observable<User> GetUserInfoUseCase and a Observable<List<Message>> GetUserLatestMessages and merge them somehow in my presenter? If yes, how can I manage this, as I don't have the Observables in my Presenter (I'm passing only an Observer as my UseCases parameters)?
User Entity
public abstract class User {
public abstract long id();
public abstract String name();
...
}
Message Entity
public abstract class Message {
public abstract long id();
public abstract long senderId();
public abstract String text();
public abstract long timstamp();
...
}
GetUsersUseCase
public class GetUsersUseCase extends UseCaseObservableWithParameter<Boolean, List<User>, UsersRepository> {
#Inject
public GetUsersUseCase(UsersRepository UsersRepository,
#Named("Thread") Scheduler threadScheduler,
#Named("PostExecution") Scheduler postExecutionScheduler) {
super(usersRepository, threadScheduler, postExecutionScheduler);
}
#Override
protected Observable<List<User>> buildObservable(Boolean forceRefresh) {
if(forceRefresh)
repository.invalidateCache();
return repository.getUsers();
}
}
UsersPresenter
public class UsersPresenter extends BasePresenter<UsersContract.View> implements UsersContract.Presenter {
#Inject
GetUsersUseCase mGetUsersUseCase;
#Inject
UserViewModelMapper mUserMapper;
#Inject
public UsersPresenter() {
}
#Override
public void attachView(UsersContract.View mvpView) {
super.attachView(mvpView);
}
#Override
public void detachView() {
super.detachView();
mGetUsersUseCase.unsubscribe();
}
#Override
public void fetchUsers(boolean forceRefresh) {
getMvpView().showProgress();
mGetUsersUseCase.execute(forceRefresh, new DisposableObserver<List<User>>() {
#Override
public void onNext(List<User> users) {
getMvpView().hideProgress();
getMvpView().showUsers(mUsersMapper.mapUsersToViewModels(users));
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
getMvpView().hideProgress();
getMvpView().showErrorMessage(e.getMessage());
}
});
}
}
UseCaseObservableWithParameter
public abstract class UseCaseObservableWithParameter<REQUEST_DATA, RESPONSE_DATA, REPOSITORY> extends UseCase<Observable, REQUEST_DATA, RESPONSE_DATA, REPOSITORY> {
public UseCaseObservableWithParameter(REPOSITORY repository, Scheduler threadScheduler, Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
protected abstract Observable<RESPONSE_DATA> buildObservable(REQUEST_DATA requestData);
public void execute(REQUEST_DATA requestData, DisposableObserver<RESPONSE_DATA> useCaseSubscriber) {
this.disposable.add(
this.buildObservable(requestData)
.subscribeOn(threadScheduler)
.observeOn(postExecutionScheduler)
.subscribeWith(useCaseSubscriber)
);
}
}
UseCase
public abstract class UseCase<OBSERVABLE, REQUEST_DATA, RESPONSE_DATA, REPOSITORY> {
protected final REPOSITORY repository;
protected final Scheduler threadScheduler;
protected final Scheduler postExecutionScheduler;
protected CompositeDisposable disposable = new CompositeDisposable();
public UseCase(REPOSITORY repository,
#Named("Thread") Scheduler threadScheduler,
#Named("PostExecution") Scheduler postExecutionScheduler) {
Timber.d("UseCase CTOR");
this.repository = repository;
this.threadScheduler = threadScheduler;
this.postExecutionScheduler = postExecutionScheduler;
}
protected abstract OBSERVABLE buildObservable(REQUEST_DATA requestData);
public boolean isUnsubscribed() {
return disposable.size() == 0;
}
public void unsubscribe() {
if (!isUnsubscribed()) {
disposable.clear();
}
}
}
Quite a lot questions within a single question. let me try to consolidate what I think I understood are ur key questions
Can Entities reference each other? the answer would be: YES. Also in
Clean Architecture u can create a domain model where entities are interconnected
What should be returned from a UseCase?
Answer: UseCases define input DTOs (Data transfer objects) and output DTOs which are most convenient for the use case. in his book uncle bob writes that entities should not be passed to use cases or returned from use cases
What is the role of the presenter then? Answer: ideally a presenter is converting data only. It converts data which is most convenient for one layer into data which is most convenient for the other layer.
hope this guidance helps u to answer ur detailed questions
More details and examples you can find in my recent posts:
https://plainionist.github.io/Implementing-Clean-Architecture-UseCases/
and
https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/
Basically, you want to push your "instrumental" aware code as far as possible (on the circle).
Use cases are very close to the model and contain a lot of business logic - you want this layer very clean to be able to do quick and easy unit tests. So, this layer shouldn't know anything about storage.
But the fun part is when Room enters the room :) Room makes it so easy to have model-like objects that you can use around and IMO it's a grey area should you use Room annotated classes for your model or not.
If you think about Room objects as Data Layer objects, then you should map them to your business objects before reaching use cases.
If you use Room as a built-in mapper of DAO to model objects, then IMO you can use them in your use cases, although clean purists probably would not agree on this.
My pragmatic advice would be - if your model has a complex structure built in from multiple entities then have a dedicated model class for it and map entities to it.
If you have something like an Address, IMO just go with the Room entity.

How to create an Observable in Android?

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.

RxJava as event bus?

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

How to create an Observable from OnClick Event Android?

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()

Categories

Resources