Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Model View Intent - An Introduction
Search
Jossi Wolf
August 16, 2017
Programming
0
150
Model View Intent - An Introduction
Jossi Wolf
August 16, 2017
Tweet
Share
More Decks by Jossi Wolf
See All by Jossi Wolf
Understanding Recomposition Performance Pitfalls
jossiwolf
3
240
DC SF - Hitchhiking Through Jetpack Compose
jossiwolf
2
370
[DC SF 2022] Hitchhiking through Jetpack Compose
jossiwolf
2
400
[Berlin 2021] Hitchhiker's Guide to Compose
jossiwolf
4
670
From LiveData to Coroutines & Flow - DevFest ZA
jossiwolf
2
190
From LiveData to Coroutines & Flow - Android Summit
jossiwolf
2
170
From LiveData to Coroutines & Flow
jossiwolf
1
700
Experimenting with the Kotlin Compiler
jossiwolf
0
400
From Java to Kotlin Multiplatform - DevFest Nuremberg
jossiwolf
0
130
Other Decks in Programming
See All in Programming
乱雑なコードの整理から学ぶ設計の初歩
masuda220
PRO
29
11k
Vueで学ぶデータ構造入門 リンクリストとキューでリアクティビティを捉える / Vue Data Structures: Linked Lists and Queues for Reactivity
konkarin
1
180
SUZURIの規約違反チェックにおけるクリエイタフィードバックの試⾏錯誤/Trial and Error in Creator Feedback for SUZURI's Terms of Service Violation Checks
ae14watanabe
1
140
「正規表現をつくる」をつくる / make "make regex"
makenowjust
1
310
レイトレZ世代に捧ぐ、今からレイトレを始めるための小径
ichi_raven
0
270
JEP 496 と JEP 497 から学ぶ耐量子計算機暗号入門 / Learning Post-Quantum Crypto Basics from JEP 496 & 497
mackey0225
2
210
Swift Concurrency 年表クイズ
omochi
3
230
詳細の決定を遅らせつつ実装を早くする
shimabox
1
1k
SidekiqでAIに商品説明を生成させてみた
akinko_0915
0
130
Atomics APIを知る / Understanding Atomics API
ssssota
1
130
オフライン対応!Flutterアプリに全文検索エンジンを実装する @FlutterKaigi2025
itsmedreamwalker
2
180
Private APIの呼び出し方
kishikawakatsumi
2
860
Featured
See All Featured
How to Ace a Technical Interview
jacobian
280
24k
GitHub's CSS Performance
jonrohan
1032
470k
For a Future-Friendly Web
brad_frost
180
10k
Building Applications with DynamoDB
mza
96
6.7k
The Power of CSS Pseudo Elements
geoffreycrofte
80
6.1k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
31
2.7k
Into the Great Unknown - MozCon
thekraken
40
2.2k
Designing for humans not robots
tammielis
254
26k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
1.8k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
Transcript
Model View Intent An Introduction
Jossi Wolf Android Developer About Me
MVI MVP MVC MVVM Redux Flux God-like Activities
Model View Intent
None
A B C data data Unidirectional Data Flow D data
data
A B C data data Unidirectional Data Flow D data
data
someModel.set(…) Immutability
someModel.set(…) Immutability
String calendar = "calendar"; System.out.println(calendar.toUpperCase()); // CALENDAR Pure Functions
public class SchoolsViewState { boolean loading; Throwable error; List<SchoolsModel> schools;
} State Model
Data Flow in MVI View Intents (User Actions) Business Logic
emits Presenter Model
public interface SchoolsViewPresenterContract { interface SchoolsViewActions { } interface SchoolsPresenterActions
{ } }
interface SchoolsPresenterActions { void loadSchools(); }
interface SchoolsViewActions { void showLoading(); void showSuccess(); void showError(); }
interface SchoolsViewActions { void render(SchoolsViewState state); }
public class SchoolsActivity implements SchoolsViewActions { @Override public void render(SchoolsViewState
state) { // The view decides how to render the state } }
@Override public void render(SchoolsViewState state) { if (state.getError() != null)
{ showError(state.getError().getMessage()); } if (state.isLoading()) { showLoader(); clearAdapter(); } else if (!state.isLoading()) { hideLoader(); } if (state.getSchools() != null) { showSchools(state.getSchools()); } }
public class ExampleStateModel { private boolean loading; private Throwable error;
private List<SchoolsModel> data; ExampleStateModel(boolean loading, Throwable error, List<SchoolsModel> data) { // set everything } }
public class ExampleStateModel { private boolean loading; private Throwable error;
private List<SchoolsModel> data; private ExampleStateModel( boolean loading, Throwable error, List<SchoolsModel> data) { // set everything } }
public static SchoolsViewState LoadingState() { return new SchoolsViewState(true, null, null);
} public static SchoolsViewState ErrorState(Throwable error) { return new SchoolsViewState(false, error, null); } public static SchoolsViewState DataLoadedState(List<SchoolsModel> schools) { return new SchoolsViewState(false, null, schools); }
State Reducer
HomeViewState { loading = false error = null data =
[…] }
HomeViewState { loading = false error = null data =
[a, b, c] } HomeViewState { loading = false error = null data = [x, y, z] } [a, b, c, x, y, z]
@Test public void loadSchoolsSuccessful() { when(api.getHamburgSchools()) .thenReturn(Observable.just(generateFakeList())); schoolsPresenter.loadSchools(); verify(schoolsView).render(SchoolsViewState.LoadingState()); verify(schoolsView).render(SchoolsViewState.DataLoadedState(generateFakeList()));
}
@Test public void loadSchoolsNotSuccessful() { Throwable throwable = new Throwable();
when(api.getHamburgSchools()) .thenReturn(Observable.error(throwable)); schoolsPresenter.loadSchools(); verify(schoolsView).render(SchoolsViewState.LoadingState()); verify(schoolsView).render(SchoolsViewState.ErrorState(throwable)); }
Predictability = = + ?
Predictability = = =
Predictability LoadingState DataLoadedState ErrorState
Readable Code Presenter View Interactor Database Network void a( )
void b( )
None
Reading on https://github.com/jossiwolf/MVI-Example https://www.youtube.com/watch?v=0IKHxjkgop4 http://hannesdorfmann.com/android/mosby3-mvi-1 https://github.com/oldergod/android-architecture
public MainViewState reduce(MainViewState previous, MainViewState next) { MainViewState computedViewState =
MainViewState.Companion.ErrorState(new Throwable("No State")); if (next.getLoading()) { computedViewState = MainViewState.Companion.LoadingState(); } else if (next.getError() != null) { computedViewState = MainViewState.Companion.ErrorState(next.getError()); } else if (next.getData() != null) { List<String> data = new ArrayList<>(); if (previous.getData() != null) { data.addAll(previous.getData()); } data.addAll(next.getData()); computedViewState = MainViewState.Companion.DataLoadedState(data); } return computedViewState; }