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
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
480
Oh, the places you'll go! Cracking Navigation on Android
brittbarak
0
500
Other Decks in Technology
See All in Technology
スピンアウト講座06_認証系(API-OAuth-MCP)入門
overflowinc
0
1.3k
FlutterでPiP再生を実装した話
s9a17
0
200
私がよく使うMCPサーバー3選と社内で安全に活用する方法
kintotechdev
0
120
How to install a gem
indirect
0
1.7k
【PHPerKaigi2026】OpenTelemetry SDKを使ってPHPでAPMを自作する
fendo181
1
300
AWS Systems Managerのハイブリッドアクティベーションを使用したガバメントクラウド環境の統合管理
toru_kubota
1
170
OpenClawでPM業務を自動化
knishioka
1
230
SSoT(Single Source of Truth)で「壊して再生」する設計
kawauso
2
370
Phase01_AI座学_基礎
overflowinc
0
4.2k
Embeddings : Symfony AI en pratique
lyrixx
0
350
【社内勉強会】新年度からコーディングエージェントを使いこなす - 構造と制約で引き出すClaude Codeの実践知
nwiizo
25
13k
来期の評価で変えようと思っていること 〜AI時代に変わること・変わらないこと〜
estie
0
110
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
269
14k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.5k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
55k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
10k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
1
160
Site-Speed That Sticks
csswizardry
13
1.1k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.7k
A designer walks into a library…
pauljervisheath
210
24k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
980
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.2k
Being A Developer After 40
akosma
91
590k
What does AI have to do with Human Rights?
axbom
PRO
1
2.1k
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 !