Up to Last time, I got the data from the API and brought it to the ViewModel. This time, I will explain the part to bring from ViewModel to View, event processing.
Please refer to here for the prerequisites of the code explained here.
You need to notify View (Activity and Fragment) of the result of asynchronous processing (such as api) from ViewModel. At this time, if the return value is received in the synchronous processing, the Main Thread will be frozen. Also, if the ViewModel has a View reference, you need to be aware of the life cycle in the ViewModel, View is not necessary because View is required for unit testing of ViewModel. Therefore, I use an event to receive it only when the View is alive.
EventBus is a well-known library for handling events. The reason for using RxBus this time is There was a story that the notification of EventBus was difficult to understand, so I chose RxBus.
This is because EventBus registers the event globally, Looking now, it seems that it depends on the implementation as follows. https://qiita.com/subaru44k/items/27cd4828edc65cd9d7a6
In that sense, EventBus might have been good considering the learning cost, Another advantage of using RxBus is that the libraries used can be integrated with asynchronous processing. There is no reason to use RxBus just because you are using RxJava. RxJava and EventBus are also OK.
I think that this area should be selected according to the situation of the team.
In RxBus, by accessing the same instance of RxBus at the place you use (for example, View and ViewModel), It enables the exchange of events. I try to get an instance of RxBus in a singleton. Event registration and monitoring can now be loosely coupled from anywhere.
Initially, Application had an instance, When I run a unit test, I can't run it without Application, so I made it a singleton. If you run the test with Android Test, it will work, so I wonder if it was okay, I'm using a singleton now.
When using it in View, if you do not release the registered event along the life cycle, It can leak or result in an error without a reference. I'll explain the details later, but when the Activity or Fragment turns behind or is released, You also need to unmonitor the event.
First, define RxBus. The source is here.
public class RxBus {
private final PublishSubject<Object> bus = PublishSubject.create();
private static RxBus rxBus;
private RxBus() {
}
public static RxBus getInstance() {
if (rxBus == null) {
rxBus = new RxBus();
}
return rxBus;
}
public void send(final Object event) {
bus.onNext(event);
}
public Observable<Object> toObservable() {
return bus;
}
public boolean hasObservers() {
return bus.hasObservers();
}
}
Define an instance of PublishSubject
that actually registers the event,
Defined to return its own instance as a singleton.
It is a process that actually uses RxBus and passes the result obtained asynchronously from the API to View. The source is here.
GithubRepositoryApiCompleteEventEntity eventResult = new GithubRepositoryApiCompleteEventEntity();
eventResult.setListItems(data);
if (response.getItems() != null && response.getItems().size() > 0) {
eventResult.setResult(true);
}
//Call an event
RxBus.getInstance().send(eventResult);
The acquired data and the acquisition result are stored in the Entity used for exchanging events called GithubRepositoryApiCompleteEventEntity
.
Specify this instance as an event argument and send the event.
It is a process to receive the event sent by RxBus. The source is here.
this.compositeDisposable = new CompositeDisposable();
this.compositeDisposable.add(RxBus.getInstance()
.toObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object obj) {
if (obj instanceof GithubRepositoryApiCompleteEventEntity) {
//List results
if (((GithubRepositoryApiCompleteEventEntity) obj).isResult()) {
RecyclerView list = view.findViewById(R.id.githubRepositoryList);
list.setLayoutManager(new LinearLayoutManager(view.getContext()));
list.setAdapter(new GithubRepositoryListAdapter(((GithubRepositoryApiCompleteEventEntity) obj).getListItems()));
list.setVisibility(View.VISIBLE);
list.addItemDecoration(new DividerItemDecoration(view.getContext(), DividerItemDecoration.VERTICAL));
}
view.findViewById(R.id.progressBar).setVisibility(View.GONE);
}
//Do not handle other events
}
}));
ExpApplication.getInstance().getViewModelLocator().getGithubRepositoryListViewModel().getRepositoryListData();
//~ Omitted ~
@Override
public void onStop() {
super.onStop();
this.compositeDisposable.clear();
}
@Override
public void onDestroy() {
super.onDestroy();
this.compositeDisposable.clear();
}
Define an instance of CompositeDisposable
and
Set RxBus event reception processing to this.
By calling CompositeDisposable.clear ()
with onStop () or onDestroy () and canceling monitoring,
It can be processed along the life cycle.
RxBus event reception processing calls .toObservable ()
and then
Specifies the thread to process with .observeOn (AndroidSchedulers.mainThread ())
.
Since I'm messing with the screen, I'm using Main Thread this time,
You can also run it in a thread different from Main with Schedulers.newThread ()
.
.subscribe (new Consumer <Object> () {
The specific reception process is described after.
public void accept (Object obj) {
The following is the reception process,
The argument specified in the transmission process is sent as an Object type variable.
ʻIf (obj instanceof GithubRepositoryApiCompleteEventEntity) {`determine the type and
It is determined whether it is an event you want to receive.
If it is an event to be received, it will be processed.
So, I tried to explain RxBus. Next time, I would like to explain sqLite by room.
Recommended Posts