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
320
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
120
Kids, Play Nice! Kotlin-Java Interop In Mind
brittbarak
2
390
Sharing is Caring- Getting Started with Kotlin Multiplatform
brittbarak
2
2k
Between JOMO and FOMO: You are reshaping communication.
brittbarak
2
1.2k
Build Apps For The Ones You Love
brittbarak
1
110
What an ML-ful World! MLKit for Android dev.
brittbarak
0
130
Make your app dance with MotionLayout
brittbarak
8
1.3k
Who's afraid of ML? V2 : First steps with MlKit
brittbarak
1
450
Oh, the places you'll go! Cracking Navigation on Android
brittbarak
0
470
Other Decks in Technology
See All in Technology
現場で役立つAPIデザイン
nagix
29
10k
バックエンドエンジニアのためのフロントエンド入門 #devsumiC
panda_program
16
6.5k
SCSAから学ぶセキュリティ管理
masakamayama
0
140
Datadog APM におけるトレース収集の流れ及び Retention Filters のはなし / datadog-apm-trace-retention-filters
k6s4i53rx
0
320
『AWS Distinguished Engineerに学ぶ リトライの技術』 #ARC403/Marc Brooker on Try again: The tools and techniques behind resilient systems
quiver
0
130
君も受託系GISエンジニアにならないか
sudataka
1
370
第13回 Data-Centric AI勉強会, 画像認識におけるData-centric AI
ksaito_osx
0
360
RSNA2024振り返り
nanachi
0
500
Fintech SREの挑戦 PCI DSS対応をスマートにこなすインフラ戦略/Fintech SRE’s Challenge: Smart Infrastructure Strategies for PCI DSS Compliance
maaaato
0
450
【Developers Summit 2025】プロダクトエンジニアから学ぶ、 ユーザーにより高い価値を届ける技術
niwatakeru
2
890
7日間でハッキングをはじめる本をはじめてみませんか?_ITエンジニア本大賞2025
nomizone
2
1.4k
Nekko Cloud、 これまでとこれから ~学生サークルが作る、 小さなクラウド
logica0419
2
730
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.2k
Speed Design
sergeychernyshev
25
780
Being A Developer After 40
akosma
89
590k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
4
400
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
3
310
Building Your Own Lightsaber
phodgson
104
6.2k
VelocityConf: Rendering Performance Case Studies
addyosmani
328
24k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
How to train your dragon (web standard)
notwaldorf
90
5.8k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
Building Flexible Design Systems
yeseniaperezcruz
328
38k
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 !