Speaker details in the Open Event Orga App
The Open Event Organiser Android App is currently released in the Alpha phase on the Google Play Store here. This blog post explains how the speaker details feature has been implemented in the app. Model The model for Speaker is pretty straightforward. It includes the personal details of the speaker such as name, biography, country, social media profiles, designation etc. Apart from these details, every instance of speaker is associated with a single event. A speaker will also have multiple instances of sessions. Full implementation of the speaker’s model can be found here. Network Call We use Retrofit in order to make the network call and Jackson Factory to deserialize the data received from the call into an instance of the speaker model. The following endpoint provides us with the required information: https://open-event-api-dev.herokuapp.com/speakers/{speaker_id} Repository In any typical android application using both network calls and data persistence, there is a need of a repository class to handle them. Speaker Repository handles the network call to the API in order to fetch the speaker details. It then saves the data returned by the api into the database asynchronously. It also ensures that we send the latest data that we have stored in the database to the view model. Given below is the full implementation for reference: @Override public Observable<Speaker> getSpeaker(long speakerId, boolean reload) { Observable<Speaker> diskObservable = Observable.defer(() -> repository .getItems(Speaker.class, Speaker_Table.id.eq(speakerId)).take(1) ); Observable<Speaker> networkObservable = Observable.defer(() -> speakerApi.getSpeaker(speakerId) .doOnNext(speaker -> repository .save(Speaker.class, speaker) .subscribe())); return repository .observableOf(Speaker.class) .reload(reload) .withDiskObservable(diskObservable) .withNetworkObservable(networkObservable) .build(); } ViewModel The View Model is responsible for fetching the necessary details from the repository and displaying it in the view. It handles all the view binding logic. The most important method in the SpeakerDetailsViewModel is the getSpeakers method. It accepts a speaker id from the fragment, queries the repository for the details of the speaker and returns it back to the fragment in the form of a LiveData. Below is the full implementation of the getSpeakers method: protected LiveData<Speaker> getSpeaker(long speakerId, boolean reload) { if (speakerLiveData.getValue() != null && !reload) return speakerLiveData; compositeDisposable.add(speakerRepository.getSpeaker(speakerId, reload) .compose(dispose(compositeDisposable)) .doOnSubscribe(disposable -> progress.setValue(true)) .doFinally(() -> progress.setValue(false)) .doOnNext(speaker -> speakerLiveData.setValue(speaker)) .flatMap(speaker -> sessionRepository.getSessionsUnderSpeaker(speakerId, reload)) .toList() .subscribe(sessionList -> sessionLiveData.setValue(sessionList), throwable -> error.setValue(ErrorUtils.getMessage(throwable)))); return speakerLiveData; } We add the disposable to a composite disposable and dispose it in the onCleared method of the View Model. The full implementation of the View Model can be found here. Fragment The SpeakerDetailsFragment acts as the view and is responsible for everything the user sees on the screen. It accepts the id of the speaker whose details are to be displayed in the constructor. When an instance of the fragment is created it sets up it’s view model and inflates it’s layout using the Data binding framework. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { context = getContext(); binding = DataBindingUtil.inflate(inflater, R.layout.speaker_details_fragment, container, false); speakerDetailsViewModel = ViewModelProviders.of(this, viewModelFactory).get(SpeakerDetailsViewModel.class); speakerId = getArguments().getLong(SPEAKER_ID); AppCompatActivity activity = ((AppCompatActivity) getActivity()); activity.setSupportActionBar(binding.toolbar); ActionBar actionBar = activity.getSupportActionBar(); if (actionBar != null) { actionBar.setHomeButtonEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true); }…
