Architecture with RxJava
Jolanda Verhoef
Blendle
Makes the world’s best
journalism available to
everyone, everywhere
@lojanda
Blendle
Makes the world’s best
journalism available to
everyone, everywhere
@lojanda
Architecture
@lojanda
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
@lojanda
Reactive Programming
@lojanda
Today’s subjects
Building standalone UI components
Building real standalone UI components
Synchronising UI components throughout the app
Updating lists after user interaction
@lojanda
Today’s subjects
Building standalone UI components
Building real standalone UI components
Synchronising UI components throughout the app
Updating lists after user interaction
@lojanda
Standalone UI componentsOpening the Blendle Reader
@lojanda
Standalone UI componentsOpening the Blendle Reader
@lojanda
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
@lojanda
ArticlePreviewRepositorypublic Single<ArticlePreview> articlePreview$( String articleId ) { if ( cache.contains( articleId ) { return Single.just( cache.retrieve( articleId )); } else { return urlResolver.urlFor( articleId ) .flatMap( blendleApi::articlePreview$ ) .doOnSuccess( cache::store ); } }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
GetArticlePreviewUseCase
public Single<ArticlePreview> execute( String articleId ) { return articleRepository.articlePreview$( articleId ) .subscribeOn( Schedulers.io() ) .observeOn( AndroidSchedulers.mainThread() ); }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
ReaderPresenter
public void init( String articleId ) { getArticlePreviewUseCase.execute( articleId ) .subscribe( getView()::showArticlePreview, getView()::loadArticlePreviewFailed ); }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
Today’s subjects
Building standalone UI components
Building real standalone UI components
Synchronising UI components throughout the app
Updating lists after user interaction
@lojanda
Standalone UI components++Inside the Blendle Reader
@lojanda
@lojanda
ReaderFragment
@lojanda
ReaderFragment
Toolbar
Featured Image
RecyclerView
@lojanda
ReaderFragment
Toolbar
Featured Image
RecyclerView
Publisher Logo
Bookmark Icon
Share Icon
Text Row
Image Row
……. Row
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
@lojanda
@lojanda
ArticleContextStore
private BehaviorSubject<String> subject;
public void changeArticleContext( final String newArticleId ) { subject.onNext( newArticleId ); }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
Reader@Override public View onCreateView( … ) { presenter.init( getArguments() != null ? getArguments().getInt( EXTRA_ARTICLE_ID ) : null ); }
@lojanda
public void init( @Nullable String articleId ) { if( articleId == null) articleId = articleContextStore.getArticleContext(); loadData( articleId ); }
VIE
WP
RE
SEN
TE
R
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
Today’s subjects
Building standalone UI components
Building real standalone UI components
Synchronising UI components throughout the app
Updating lists after user interaction
@lojanda
Synchronising UI componentsBookmarking an article
@lojanda
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
@lojanda
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
BookmarkStoreprivate Map<String, BehaviorSubject<Boolean>> subjectMap;
public BehaviorSubject<Boolean> getBookmarked( String articleId ) { if( subjectMap.contains( articleId ) return subjectMap.get( articleId ); BehaviorSubject<Boolean> subject = BehaviorSubject.create(); subjectMap.put( articleId, subject ); return subject; }
public void setBookmarked( String articleId, Boolean bookmarked ) { getBookmarked().onNext( bookmarked ); }
@lojanda
BookmarkRepositorypublic Observable<Boolean> bookmarked$( String articleId ) { BehaviorSubject<Boolean> subject = bookmarkStore .getBookmarked( articleId );
if( ! subject.hasValue() ) { this.bookmarkedCall( articleId ) .subscribe( bookmarkStore::setBookmarked ); }
return subject; }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
GetBookmarkUseCase
public Observable<Boolean> execute( String articleId ) { return bookmarkRepository.bookmarked$( articleId ) .subscribeOn( Schedulers.io() ) .observeOn( AndroidSchedulers.mainThread() ); }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
BookmarkPresenter
public void init( String articleId ) { getBookmarkUseCase.execute( articleId ) .subscribe( getView()::showBookmarkValue ); }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
Today’s subjects
Building standalone UI components
Building real standalone UI components
Synchronising UI components throughout the app
Updating lists after user interaction
@lojanda
Updating listsArticle reading list
@lojanda
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
@lojanda
@lojanda
Mutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
BookmarkStoreprivate PublishSubject<Pair<String, Boolean>> subject;
public Observable<Boolean> getBookmarkListener() { return subject; }
public void setBookmarked( String articleId, Boolean bookmarked ) { getBookmarked( articleId ).onNext( bookmarked ); subject.onNext( new Pair<>( articleId, bookmarked ); }
@lojanda
ReadingListPresenterpublic void init() { bookmarkStore.getBookmarkListener() .subscribe( this::bookmarkChanged ); }
public void bookmarkChanged( Pair<String, Boolean> pair ) { String articleId = pair.first; Boolean newBookmarkValue = pair.second; if( newBookmarkValue ) { getView().addBookmark( articleId ); } else { getView().removeBookmark( articleId ); } }
@lojandaMutable Data Stores
Context Stores
Mutable Data RepositoriesStatic Data
Repositories
Business Use Cases
Presenters
Custom Views Fragments Activities
Today’s subjects
Building standalone UI components
Building real standalone UI components
Synchronising UI components throughout the app
Updating lists after user interaction
@lojanda
Questions?Architecture https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
Static datahttp://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/
Mutable data http://reactivex.io/RxJava/javadoc/rx/subjects/BehaviorSubject.html
http://reactivex.io/RxJava/javadoc/rx/subjects/PublishSubject.html
https://lorentzos.com/rxjava-as-event-bus-the-right-way-10a36bdd49ba
@lojanda