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
160
0
Share
Model View Intent - An Introduction
Jossi Wolf
August 16, 2017
More Decks by Jossi Wolf
See All by Jossi Wolf
Understanding Recomposition Performance Pitfalls
jossiwolf
3
280
DC SF - Hitchhiking Through Jetpack Compose
jossiwolf
2
410
[DC SF 2022] Hitchhiking through Jetpack Compose
jossiwolf
2
440
[Berlin 2021] Hitchhiker's Guide to Compose
jossiwolf
4
690
From LiveData to Coroutines & Flow - DevFest ZA
jossiwolf
2
220
From LiveData to Coroutines & Flow - Android Summit
jossiwolf
2
190
From LiveData to Coroutines & Flow
jossiwolf
1
720
Experimenting with the Kotlin Compiler
jossiwolf
0
500
From Java to Kotlin Multiplatform - DevFest Nuremberg
jossiwolf
0
160
Other Decks in Programming
See All in Programming
Agentic Elixir
whatyouhide
0
440
「Linuxサーバー構築標準教科書」を読んでみた #ツナギメオフライン.7
akase244
0
1.4k
Firefoxにコントリビューションして得られた学び
ken7253
2
150
Symfony AI in Action - SymfonyLive Berlin 2026
chr_hertel
1
120
t *testing.T は どこからやってくるの?
otakakot
1
910
when storing skills in S3 file
watany
3
1.3k
リセットCSSを1行消したらアクセシビリティが向上した話
pvcresin
4
490
クラウドネイティブなエンジニアに向ける Raycastの魅力と実際の活用事例
nealle
2
250
2026年のソフトウェア開発を考える(2026/05版) / Software Engineering Scrum Fest Niigata 2026 Edition
twada
PRO
21
11k
🦞OpenClaw works with AWS
licux
1
340
PHPでバイナリをパースして理解するASN.1
muno92
PRO
0
430
Liberating Ruby's Parser from Lexer Hacks
ydah
2
2.6k
Featured
See All Featured
Designing Powerful Visuals for Engaging Learning
tmiket
1
360
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
260
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
380
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.9k
Git: the NoSQL Database
bkeepers
PRO
432
67k
Context Engineering - Making Every Token Count
addyosmani
9
870
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
How to build a perfect <img>
jonoalderson
1
5.5k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
180
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.9k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
270
Principles of Awesome APIs and How to Build Them.
keavy
128
17k
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; }