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
組織貢献をするフリーランスエンジニアという生き方
n_takehata
1
1k
アジャイル開発とスクラム
araihara
0
160
WAF に頼りすぎない AWS WAF 運用術 meguro sec #1
izzii
0
460
FastConnect の冗長性
ocise
1
9.6k
飲食店予約台帳を支えるインタラクティブ UI 設計と実装
siropaca
6
1.4k
データの品質が低いと何が困るのか
kzykmyzw
6
1k
転生CISOサバイバル・ガイド / CISO Career Transition Survival Guide
kanny
3
410
Datadog APM におけるトレース収集の流れ及び Retention Filters のはなし / datadog-apm-trace-retention-filters
k6s4i53rx
0
320
Data-centric AI入門第6章:Data-centric AIの実践例
x_ttyszk
1
370
滅・サービスクラス🔥 / Destruction Service Class
sinsoku
6
1.5k
MC906491 を見据えた Microsoft Entra Connect アップグレード対応
tamaiyutaro
1
480
地方拠点で エンジニアリングマネージャーってできるの? 〜地方という制約を楽しむオーナーシップとコミュニティ作り〜
1coin
1
130
Featured
See All Featured
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
How to Ace a Technical Interview
jacobian
276
23k
Writing Fast Ruby
sferik
628
61k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.4k
Facilitating Awesome Meetings
lara
51
6.2k
YesSQL, Process and Tooling at Scale
rocio
171
14k
How STYLIGHT went responsive
nonsquared
98
5.3k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
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 !