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
140
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
210
DC SF - Hitchhiking Through Jetpack Compose
jossiwolf
2
330
[DC SF 2022] Hitchhiking through Jetpack Compose
jossiwolf
2
370
[Berlin 2021] Hitchhiker's Guide to Compose
jossiwolf
4
630
From LiveData to Coroutines & Flow - DevFest ZA
jossiwolf
2
160
From LiveData to Coroutines & Flow - Android Summit
jossiwolf
2
150
From LiveData to Coroutines & Flow
jossiwolf
1
670
Experimenting with the Kotlin Compiler
jossiwolf
0
330
From Java to Kotlin Multiplatform - DevFest Nuremberg
jossiwolf
0
100
Other Decks in Programming
See All in Programming
dbt Pythonモデルで実現するSnowflake活用術
trsnium
0
260
コミュニティ駆動 AWS CDK ライブラリ「Open Constructs Library」 / community-cdk-library
gotok365
2
250
Rubyと自由とAIと
yotii23
6
1.8k
CDK開発におけるコーディング規約の運用
yamanashi_ren01
2
260
『テスト書いた方が開発が早いじゃん』を解き明かす #phpcon_nagoya
o0h
PRO
9
2.5k
[JAWS DAYS 2025] 最近の DB の競合解決の仕組みが分かった気になってみた
maroon1st
0
130
iOSでQRコード生成奮闘記
ktcryomm
2
110
Honoをフロントエンドで使う 3つのやり方
yusukebe
7
3.6k
Generating OpenAPI schema from serializers throughout the Rails stack - Kyobashi.rb #5
envek
1
390
Better Code Design in PHP
afilina
0
180
第3回関東Kaggler会_AtCoderはKaggleの役に立つ
chettub
3
1.2k
PRレビューのお供にDanger
stoticdev
1
240
Featured
See All Featured
Done Done
chrislema
182
16k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
12
1k
Facilitating Awesome Meetings
lara
52
6.2k
A Tale of Four Properties
chriscoyier
158
23k
Embracing the Ebb and Flow
colly
84
4.6k
Designing for Performance
lara
604
68k
Six Lessons from altMBA
skipperchong
27
3.6k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
The Pragmatic Product Professional
lauravandoore
32
6.4k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Automating Front-end Workflow
addyosmani
1368
200k
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; }