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
Clean, Easy & New Android Arch. : Devoxx-BE 17
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Britt Barak
November 09, 2017
Technology
3
340
Clean, Easy & New Android Arch. : Devoxx-BE 17
Britt Barak
November 09, 2017
Tweet
Share
More Decks by Britt Barak
See All by Britt Barak
[Vonage] Introducing Conversations
brittbarak
1
140
Kids, Play Nice! Kotlin-Java Interop In Mind
brittbarak
2
460
Sharing is Caring- Getting Started with Kotlin Multiplatform
brittbarak
2
2.1k
Between JOMO and FOMO: You are reshaping communication.
brittbarak
2
1.3k
Build Apps For The Ones You Love
brittbarak
1
140
What an ML-ful World! MLKit for Android dev.
brittbarak
0
150
Make your app dance with MotionLayout
brittbarak
8
1.4k
Who's afraid of ML? V2 : First steps with MlKit
brittbarak
1
470
Oh, the places you'll go! Cracking Navigation on Android
brittbarak
0
490
Other Decks in Technology
See All in Technology
学生・新卒・ジュニアから目指すSRE
hiroyaonoe
2
650
量子クラウドサービスの裏側 〜Deep Dive into OQTOPUS〜
oqtopus
0
130
SchooでVue.js/Nuxtを技術選定している理由
yamanoku
3
110
AIエージェントを開発しよう!-AgentCore活用の勘所-
yukiogawa
0
170
配列に見る bash と zsh の違い
kazzpapa3
3
160
仕様書駆動AI開発の実践: Issue→Skill→PRテンプレで 再現性を作る
knishioka
2
680
OWASP Top 10:2025 リリースと 少しの日本語化にまつわる裏話
okdt
PRO
3
820
Digitization部 紹介資料
sansan33
PRO
1
6.8k
Bill One 開発エンジニア 紹介資料
sansan33
PRO
5
17k
登壇駆動学習のすすめ — CfPのネタの見つけ方と書くときに意識していること
bicstone
3
120
GitHub Issue Templates + Coding Agentで簡単みんなでIaC/Easy IaC for Everyone with GitHub Issue Templates + Coding Agent
aeonpeople
1
250
Claude_CodeでSEOを最適化する_AI_Ops_Community_Vol.2__マーケティングx_AIはここまで進化した.pdf
riku_423
2
600
Featured
See All Featured
Optimising Largest Contentful Paint
csswizardry
37
3.6k
Building Adaptive Systems
keathley
44
2.9k
The SEO Collaboration Effect
kristinabergwall1
0
350
YesSQL, Process and Tooling at Scale
rocio
174
15k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
What's in a price? How to price your products and services
michaelherold
247
13k
We Have a Design System, Now What?
morganepeng
54
8k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
100
How to Talk to Developers About Accessibility
jct
2
130
Context Engineering - Making Every Token Count
addyosmani
9
660
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Transcript
Clean, Easy & New Android Architecture Britt Barak Devoxx Belgium
2017
Britt Barak @brittBarak Android Developer & TL Android Academy Women
Techmakers
And you...?
One thing is sure Everything will change. Quick.
My First Startup
“As You Like It” / W. Shakespeare ״All the world’s
a stage, And all the men and women merely players; They have their exits and their entrances, And one man in his time plays many parts:״
Players Exits and Entrances Plays a part → Single responsibility
→ Defined interfaces → Separation of concerns
Our Goals - Write quicker - Change easily - Rely
on the code (test) - Easy for others to understand
App Architecture with the new components
Who loves Jelly Beans?
None
None
None
None
Where to start?
Presentation Layer Data Layer Domain Layer
None
Is about: UI Is not about: logic. Presentation Layer
class JellyBeanViewModel extends ViewModel { String flavor; int r; int
g; int b;
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_bean); setViewModel()
setUi(); }
void setViewModel(){ this.viewModel = new JellyBeanViewModel(); }
UI represents the ViewModel state
Presentation Layer Domain Layer View ViewModel User Input
1. Update the viewModel
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { switch
(seekBar.getId()) { case R.id.sb_r: viewModel.setR(progress); break; //...
2. View Model notifies
- Callbacks - Data binding - RxJava - LiveData How
to notify?
LiveData - Observable data holder class - Lifecycle-aware - Updates
only on started / resumed state - Removes itself on destroyed state - No memory leaks https://developer.android.com/topic/libraries/architecture/livedata.html
public class JellyBeanViewModel extends ViewModel { String flavor; LiveData<Integer> r;
LiveData<Integer> g; LiveData<Integer> b;
public class JellyBeanViewModel extends ViewModel { LiveData<Integer> r; public void
setR(int r) { r = validate(r); this.r.setValue(r); }
3. Create an observer
Observer<Integer> colorChangedObserver = (Integer integer) -> { beanIv.setColorFilter(viewModel.getColor()); };
4. Observe ViewModel changes
viewModel.getR() .observe(this, colorChangedObserver); Observer is tied to this lifecycle, and
will be removed as the lifecycle ends. LivaData
Presentation Layer Domain Layer ViewModel View set() User Input notify
Persisting ViewModel
None
setViewModel() -> { this.viewModel = ViewModelProviders.of(this) .get(JellyBeanViewModel.class); }
And for more complex ViewModels?
1. Multiple LiveData Objects 2. Separate class → Lifecycle Aware
Suggestions: Peach Dream Peach Pie P
Save The Jelly Bean!
Is about: “objective” data Is not about: caring about the
consumer Data Layer
- Data Model - Repository Data Layer
class JellyBeanViewModel String flavor; int r; int g; int b;
class JellyBean String flavor; String color;
- One per data type (e.g jelly bean, recipe, user….).
- Encapsulates the logic of getting/setting the data. - CRUD operations (Create, Read, Update, Delete) Repository
class JellyBeanRepo{ }
class JellyBeanRepo{ LiveData<JellyBean> getJellyBean(String id){ }
LiveData<JellyBean> getJellyBean(String id) { return myFirebaseClient.getJellyBean(id) }
LiveData<JellyBean> getJellyBean(String id) { if (cache.hasJellyBean(id)){ return cache.getJellyBean(id); } else{
return myFirebaseClient.getJellyBean(id) } }
LiveData<JellyBean> getJellyBean(String id) { if (cache.hasJellyBean(id)){ return cache.getJellyBean(id); } else
if (appDatabase.hasJellyBean(id)) { return appDatabase.jellyBeanDao().getJellyBean(id); } else{ return myFirebaseClient.getJellyBean(id) }
LiveData<JellyBean> getJellyBean(String id) { if (cache.hasJellyBean(id)){ return cache.getJellyBean(id); } else
if (appDatabase.hasJellyBean(id)) { return appDatabase.jellyBeanDao().getJellyBean(id); } else{ return myApiClient.getJellyBean(id) }
Presentation Layer Data Layer ViewModel DataModel ?
Presentation Layer Data Layer Domain Layer DataModel Interactor ViewModel
Is about: converting models Is not about: UI, Data Domain
Layer
Save The Jelly Bean!
1. Create Use Case
class SaveJellyBean extends UseCase { void execute() { }
2. Convert Models
public class SaveJellyBean extends UseCase { public void execute(JellyBeanViewModel viewModel)
{ JellyBean data = prepareDataModel(viewModel); }
JellyBean prepareDataModel(JellyBeanViewModel viewModel){ String beanColorString = String.format("#%06X", (0xFFFFFF & viewModel.getColor()));
JellyBean data = new JellyBean(viewModel.getFlavor(), beanColorString); return data; }
3. Call Repository
public class SaveJellyBean extends UseCase { public void execute(JellyBeanViewModel viewModel)
{ JellyBean data = prepareDataModel(viewModel); repo.saveBean(data); }
4. Execute
Presentation Layer Data Layer Domain Layer DataModel Interactor ViewModel
Presentation Layer Data Layer Domain Layer SaveJellyBean .execute() JellyBeanRepo .save()
Reusing interactors - Edit Jelly Bean screen - Different UI
- Same SaveJellyBean use case
Some more about Repository...
Data Layer Network Service Local DB Cache? Domain Layer Some
Usecase
Local database - Persistence between sessions - Single source of
truth
Room - Wraps SQLite database - Generates boilerplate code -
Verifies queries at compile time - Denies calls on the UI thread
1. Create Entity
@Entity public class JellyBean { @PrimaryKey @NonNull String id; String
flavor; String color;
2. Create Dao
@Dao public interface JellyBeanDao { @Query("select * from jellyBean") LiveData<List<JellyBean>>
getAllJellyBeans(); @Query("select * from jellyBean where id = :beanId") LiveData<JellyBean> getJellyBean(String beanId); }
@Insert(onConflict = REPLACE) void insertJellyBean(JellyBean jellyBean); @Delete void deleteJellyBean(JellyBean jellyBean);
3. Create App Database instance
@Database(version = 1, entities = {JellyBean.class}) public abstract class AppDatabase
extends RoomDatabase { private static AppDatabase instance; public abstract JellyBeanDao jellyBeanDao(); //init and destroy code.. }
public static AppDatabase getInMemoryDatabase(Context appContext){ if (instance == null) {
instance = Room.inMemoryDatabaseBuilder( appContext, AppDatabase.class).build(); } return instance; } public static void destroyInstance() { instance = null; }
4. Use from Repository
public LiveData<JellyBean> getJellyBean(String id) { if (cache.hasJellyBean(id)){ //… return appDatabase.jellyBeanDao().getJellyBean(id);
//... }
Presentation Layer Data Layer Domain Layer SaveJellyBean .execute() JellyBeanRepo .save()
LocalDB JellyBeanDao
Presentation Layer • View • ViewModel • Presenter Data Layer
• Repository • DataModel Domain Layer • Interactor • Use case
Players Exits and Entrances Plays a part → Single responsibility
→ Defined interfaces → Separation of concerns
Our Goals - Write quicker - Change easily - Rely
on the code (test) - Easy for others to understand
Get my notes on - @britt.barak Keep in touch! Britt
Barak @brittBarak Thank you!
Thank You !