SlideShare a Scribd company logo
Android Design
Patterns
Godfrey Nolan
Android Application Architecture (Android Dev Summit) https://www.youtube.com/watch?v=BlkJzgjzL0c
What is Your Goal?
Scalable
Maintainable
Testing
What is Your Goal?
Scalable
Add new features quickly
Maintainable
No spaghetti code
Don't cross the streams
Testing
Easy to mock
Why?
Easier to add new features
Easier to understand
Easier to police
Make our life easier
Make Unit Testing easier
How do we get there?
https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
Android Design Patterns
Classic Android
View Model
https://github.com/konmik/konmik.github.io/wiki/Introduction-to-Model-View-Presenter-on-Android
Android Design Patterns
package alexandria.israelferrer.com.libraryofalexandria;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RatingBar;
import android.widget.TextView;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.squareup.picasso.Picasso;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
public class MainActivity extends Activity {
private static final String PACKAGE = "com.israelferrer.alexandria";
private static final String KEY_FAVS = PACKAGE + ".FAVS";
private List<ArtWork> artWorkList;
private ArtWorkAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.listView);
InputStream stream = getResources().openRawResource(R.raw.artwork);
Type listType = new TypeToken<List<ArtWork>>() {
}.getType();
artWorkList = new Gson().fromJson(new InputStreamReader(stream), listType);
final SharedPreferences preferences = getSharedPreferences(getPackageName()
, Context.MODE_PRIVATE);
for (ArtWork artWork : artWorkList) {
artWork.setRating(preferences.getFloat(PACKAGE + artWork.getId(), 0F));
}
adapter = new ArtWorkAdapter();
listView.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.filter) {
adapter.orderMode();
return true;
}
return super.onOptionsItemSelected(item);
}
private class ArtWorkAdapter extends BaseAdapter {
private boolean isOrder;
private final List<ArtWork> orderedList;
public ArtWorkAdapter() {
super();
orderedList = new LinkedList<ArtWork>();
}
@Override
public int getCount() {
return artWorkList.size();
}
@Override
public Object getItem(int position) {
return artWorkList.get(position);
}
@Override
public long getItemId(int position) {
return Long.valueOf(artWorkList.get(position).getId());
}
public void orderMode() {
isOrder = !isOrder;
if (isOrder) {
orderedList.clear();
orderedList.addAll(artWorkList);
Collections.sort(orderedList);
notifyDataSetChanged();
} else {
notifyDataSetChanged();
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ArtWork artWork;
if (isOrder) {
artWork = orderedList.get(position);
} else {
artWork = artWorkList.get(position);
}
View row;
switch (artWork.getType()) {
case ArtWork.QUOTE:
row = getLayoutInflater().inflate(R.layout.text_row, null);
TextView quote = (TextView) row.findViewById(R.id.quote);
TextView author = (TextView) row.findViewById(R.id.author);
quote.setText(""" + artWork.getText() + """);
author.setText(artWork.getAuthor());
break;
case ArtWork.PAINTING:
final SharedPreferences preferences = getSharedPreferences(getPackageName()
, Context.MODE_PRIVATE);
final HashSet<String> favs = (HashSet<String>) preferences
.getStringSet(KEY_FAVS,
new HashSet<String>());
row = getLayoutInflater().inflate(R.layout.painting_row, null);
ImageView image = (ImageView) row.findViewById(R.id.painting);
TextView painter = (TextView) row.findViewById(R.id.author);
painter.setText(artWork.getTitle() + " by " + artWork.getAuthor());
Picasso.with(MainActivity.this).load(artWork.getContentUrl()).fit()
.into(image);
RatingBar rating = (RatingBar) row.findViewById(R.id.rate);
rating.setRating(artWork.getRating());
rating.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
@Override
public void onRatingChanged(RatingBar ratingBar, float rating,
boolean fromUser) {
preferences.edit().putFloat(PACKAGE + artWork.getId(), rating).apply();
artWork.setRating(rating);
}
});
CheckBox fav = (CheckBox) row.findViewById(R.id.fav);
fav.setChecked(favs.contains(artWork.getId()));
fav.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
final HashSet<String> favs = new HashSet<String>((HashSet<String>)
preferences
.getStringSet(KEY_FAVS,
new HashSet<String>()));
if (isChecked) {
favs.add(artWork.getId());
} else {
favs.remove(artWork.getId());
}
preferences.edit().putStringSet(KEY_FAVS,
favs).apply();
}
});
break;
case ArtWork.MOVIE:
case ArtWork.OPERA:
row = new ViewStub(MainActivity.this);
break;
default:
row = getLayoutInflater().inflate(R.layout.text_row, null);
}
return row;
}
}
}
Classic Android
Pros
Better the devil you know
Cons
Activities and Fragments quickly become large
Painful to make changes or add new features
All the logic in Activities, unit testing is impossible
Classic Android is not MVC
MVC
https://medium.com/@tinmegali/model-view-presenter-mvp-in-android-part-1-441bfd7998fe#.d19x8cido
Android Design Patterns
http://androidexample.com/Use_MVC_Pattern_To_Create_Very_Basic_Shopping_Cart__-_Android_Example
package com.androidexample.mvc;
//imports
public class FirstScreen extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.firstscreen);
final LinearLayout lm = (LinearLayout) findViewById(R.id.linearMain);
final Button secondBtn = (Button) findViewById(R.id.second);
//Get Global Controller Class object (see application tag in AndroidManifest.xml)
final Controller aController = (Controller) getApplicationContext();
/* ........ */
//Product arraylist size
int ProductsSize = aController.getProductsArraylistSize();
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
/******** Dynamically create view elements - Start **********/
for(int j=0;j< ProductsSize;j++)
{
// Get probuct data from product data arraylist
String pName = aController.getProducts(j).getProductName();
int pPrice = aController.getProducts(j).getProductPrice();
// Create LinearLayout to view elemnts
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
TextView product = new TextView(this);
product.setText(" "+pName+" ");
//Add textView to LinearLayout
ll.addView(product);
TextView price = new TextView(this);
price.setText(" $"+pPrice+" ");
//Add textView to LinearLayout
ll.addView(price);
final Button btn = new Button(this);
btn.setId(j+1);
btn.setText("Add To Cart");
// set the layoutParams on the button
btn.setLayoutParams(params);
package com.androidexample.mvc;
import java.util.ArrayList;
import android.app.Application;
public class Controller extends Application{
private ArrayList<ModelProducts> myProducts = new ArrayList<ModelProducts>();
private ModelCart myCart = new ModelCart();
public ModelProducts getProducts(int pPosition) {
return myProducts.get(pPosition);
}
public void setProducts(ModelProducts Products) {
myProducts.add(Products);
}
public ModelCart getCart() {
return myCart;
}
public int getProductsArraylistSize() {
return myProducts.size();
}
}
package com.androidexample.mvc;
public class ModelProducts {
private String productName;
private String productDesc;
private int productPrice;
public ModelProducts(String productName,String productDesc,int productPrice) {
this.productName = productName;
this.productDesc = productDesc;
this.productPrice = productPrice;
}
public String getProductName() {
return productName;
}
public String getProductDesc() {
return productDesc;
}
public int getProductPrice() {
return productPrice;
}
}
Android Design Patterns
MVC
Pros
No business logic in UI
Easier to unit test
Cons
Doesn't scale, separates UI but not model
Controller often grows too big
https://github.com/konmik/konmik.github.io/wiki/Introduction-to-Model-View-Presenter-on-Android
MVP
Model-View-Presenter
https://speakerdeck.com/rallat/android-development-like-a-pro
Android Design Patterns
MVP
Increases separation of concerns into 3 layers
Passive View - Render logic
Presenter - Handle User events (Proxy)
Model - Business logic
https://github.com/googlesamples/android-architecture/wiki/Samples-at-a-glance
https://www.linkedin.com/pulse/mvc-mvp-mvvm-architecture-patterns-shashank-gupta
https://github.com/erikcaffrey/Android-Spotify-MVP
public interface ArtistsMvpView extends MvpView{
void showLoading();
void hideLoading();
void showArtistNotFoundMessage();
void showConnectionErrorMessage();
void renderArtists(List<Artist> artists);
void launchArtistDetail(Artist artist);
}
public class ArtistsPresenter implements Presenter<ArtistsMvpView>, ArtistCallback {
private ArtistsMvpView artistsMvpView;
private ArtistsInteractor artistsInteractor;
public ArtistsPresenter() {
}
@Override public void setView(ArtistsMvpView view) {
if (view == null) throw new IllegalArgumentException("You can't set a null view");
artistsMvpView = view;
artistsInteractor = new ArtistsInteractor(artistsMvpView.getContext());
}
@Override public void detachView() {
artistsMvpView = null;
}
public void onSearchArtist(String string) {
artistsMvpView.showLoading();
artistsInteractor.loadDataFromApi(string, this);
}
public void launchArtistDetail(Artist artist) {
artistsMvpView.launchArtistDetail(artist);
}
//.....
}
public class ArtistsInteractor {
SpotifyService mSpotifyService;
SpotifyApp mSpotifyApp;
public ArtistsInteractor(Context context) {
this.mSpotifyApp = SpotifyApp.get(context);
this.mSpotifyService = mSpotifyApp.getSpotifyService();
}
public void loadDataFromApi(String query, ArtistCallback artistCallback) {
mSpotifyService.searchArtist(query)
.subscribeOn(mSpotifyApp.SubscribeScheduler())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(artistsSearch -> onSuccess(artistsSearch, artistCallback),
throwable -> onError(throwable, artistCallback));
}
Android Design Patterns
public class MainActivity extends Activity implements MainView, AdapterView.OnItemClickListener {
private ListView listView;
private ProgressBar progressBar;
private MainPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list);
listView.setOnItemClickListener(this);
progressBar = (ProgressBar) findViewById(R.id.progress);
presenter = new MainPresenterImpl(this);
}
@Override public void setItems(List<String> items) {
listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));
}
@Override public void showMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
presenter.onItemClicked(position);
}
}
package com.antonioleiva.mvpexample.app.main;
public interface MainPresenter {
void onResume();
void onItemClicked(int position);
void onDestroy();
}
public class MainPresenterImpl implements MainPresenter, FindItemsInteractor.OnFinishedListener {
private MainView mainView;
private FindItemsInteractor findItemsInteractor;
public MainPresenterImpl(MainView mainView) {
this.mainView = mainView;
findItemsInteractor = new FindItemsInteractorImpl();
}
@Override public void onResume() {
if (mainView != null) {
mainView.showProgress();
}
findItemsInteractor.findItems(this);
}
@Override public void onItemClicked(int position) {
if (mainView != null) {
mainView.showMessage(String.format("Position %d clicked", position + 1));
}
}
@Override public void onDestroy() {
mainView = null;
}
@Override public void onFinished(List<String> items) {
if (mainView != null) {
mainView.setItems(items);
mainView.hideProgress();
}
}
}
public interface MainView {
void showProgress();
void hideProgress();
void setItems(List<String> items);
void showMessage(String message);
}
http://antonioleiva.com/mvp-android/
MVP Testing
View
Test render logic and interaction with presenter,
mock Presenter.
Presenter
Test that view events invoke the right model
method. Mock both View and Model.
Model
Test the business logic, mock the data source and
Presenter.
MVP
Pros
Complex Tasks split into simpler tasks
Smaller objects, less bugs, easier to debug
Testable
Cons
BoilerPlate to wire the layers.
Model can’t be reused, tied to specific use case.
View and Presenter are tied to data objects since
they share the same type of object with the Model.
https://speakerdeck.com/rallat/androiddevlikeaprodroidconsf
MVVM
Microsoft Pattern
Removes UI code from Activities/Fragments
View has no knowledge of model
Data Binding = Bind ViewModel to Layout
Goodbye Presenter, hello ViewModel
http://tech.vg.no/2015/07/17/android-databinding-goodbye-presenter-hello-viewmodel/
Android Design Patterns
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/password_block"
android:id="@+id/email_block"
android:visibility="@{data.emailBlockVisibility}">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Email:"
android:minWidth="100dp"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:ems="10"
android:id="@+id/email"/>
</LinearLayout>
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
mBinding = FragmentMainBinding.bind(view);
mViewModel = new MainModel(this, getResources());
mBinding.setData(mViewModel);
attachButtonListener();
return view;
}
public void updateDependentViews() {
if (isExistingUserChecked.get()) {
emailBlockVisibility.set(View.GONE);
loginOrCreateButtonText.set(mResources.getString(R.string.log_in));
}
else {
emailBlockVisibility.set(View.VISIBLE);
loginOrCreateButtonText.set(mResources.getString(R.string.create_user));
}
}
http://tech.vg.no/2015/07/17/android-databinding-goodbye-presenter-hello-viewmodel/
MVVM
Pros
First Party Library
Compile time checking
Presentation layer in XML
Testable
Less code, no more Butterknife
Cons
Data Binding isn't always appropriate
Android Studio integration was flaky
Reactive - RxJava
Not really an architecture
Used in many other architectures
Event based Publish / Subscribe
public void doLargeComputation(
final IComputationListener listener,
final OtherParams params) {
Subscription subscription = doLargeComputationCall(params)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<Result>>>() {
@Override public void onNext(final List<Result> results) {
listener.doLargeComputationComplete(results);
}
@Override public void onCompleted() {}
@Override public void onError(final Throwable t) {
listener.doLargeComputationFailed(t);
}
}
);
}
private Observable<List<Result>> doLargeComputationCall(final OtherParams params) {
return Observable.defer(new Func0<Observable<List<Result>>>() {
@Override public Observable<List<Result>> call() {
List<Result> results = doTheRealLargeComputation(params);
if (results != null && 0 < results.size()) {
return Observable.just(results);
}
return Observable.error(new ComputationException("Could not do the large computation"));
}
}
);
}
MVC w/RxJava
https://github.com/yigit/dev-summit-architecture-demo
Clean Architecture
Uncle Bob
Much better decoupling, better reusabiity
Lots more layers
https://github.com/rallat/EffectiveAndroid
Clean Architecture is...
Independent of Frameworks
Testable
Independent of UI
Independent of Database
Independent of any External Agency
Decoupled
Android Design Patterns
Clean Architecture
https://github.com/rallat/EffectiveAndroid
Clean Architecture (Kotlin)
https://github.com/pardom/CleanNews
Android Design Patterns
tearDown()
Act Early
Trust but Verify
Know what you're getting into
YAGNI
Repos
MVC: http://androidexample.com/Use_MVC_Pattern_To_Create_Very_Basic_Shopping_Cart__-_Android_Example
MVC-Reactive: https://github.com/yigit/dev-summit-architecture-demo
MVP: https://github.com/antoniolg/androidmvp
MVVM: https://github.com/ivacf/archi
Clean: https://github.com/rallat/EffectiveAndroid
Contact Details
godfrey@riis.com
@godfreynolan
slideshare.com/godfreynolan
Ad

More Related Content

What's hot (20)

Model View Controller (MVC)
Model View Controller (MVC)Model View Controller (MVC)
Model View Controller (MVC)
Javier Antonio Humarán Peñuñuri
 
Visula C# Programming Lecture 1
Visula C# Programming Lecture 1Visula C# Programming Lecture 1
Visula C# Programming Lecture 1
Abou Bakr Ashraf
 
PUC SE Day 2019 - SpringBoot
PUC SE Day 2019 - SpringBootPUC SE Day 2019 - SpringBoot
PUC SE Day 2019 - SpringBoot
Josué Neis
 
MVP Clean Architecture
MVP Clean  Architecture MVP Clean  Architecture
MVP Clean Architecture
Himanshu Dudhat
 
Spring boot jpa
Spring boot jpaSpring boot jpa
Spring boot jpa
Hamid Ghorbani
 
Object Oriented Design Principles
Object Oriented Design PrinciplesObject Oriented Design Principles
Object Oriented Design Principles
Thang Tran Duc
 
Introduction to Android Fragments
Introduction to Android FragmentsIntroduction to Android Fragments
Introduction to Android Fragments
Sergi Martínez
 
SQLITE Android
SQLITE AndroidSQLITE Android
SQLITE Android
Sourabh Sahu
 
Acrhitecture deisign pattern_MVC_MVP_MVVM
Acrhitecture deisign pattern_MVC_MVP_MVVMAcrhitecture deisign pattern_MVC_MVP_MVVM
Acrhitecture deisign pattern_MVC_MVP_MVVM
Dong-Ho Lee
 
MVVM - Model View ViewModel
MVVM - Model View ViewModelMVVM - Model View ViewModel
MVVM - Model View ViewModel
Dareen Alhiyari
 
Try Jetpack Compose
Try Jetpack ComposeTry Jetpack Compose
Try Jetpack Compose
LutasLin
 
Spring boot
Spring bootSpring boot
Spring boot
Bhagwat Kumar
 
Declarative UIs with Jetpack Compose
Declarative UIs with Jetpack ComposeDeclarative UIs with Jetpack Compose
Declarative UIs with Jetpack Compose
Ramon Ribeiro Rabello
 
Fragment
Fragment Fragment
Fragment
nationalmobileapps
 
React js
React jsReact js
React js
Rajesh Kolla
 
Introduction to Android development - Presentation
Introduction to Android development - PresentationIntroduction to Android development - Presentation
Introduction to Android development - Presentation
Atul Panjwani
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
Giovanni Scerra ☃
 
Introduction to Android Window System
Introduction to Android Window SystemIntroduction to Android Window System
Introduction to Android Window System
National Cheng Kung University
 
Intents in Android
Intents in AndroidIntents in Android
Intents in Android
ma-polimi
 
MVC Architecture
MVC ArchitectureMVC Architecture
MVC Architecture
Prem Sanil
 

Viewers also liked (20)

From Maps to Apps the Future of Drone Technology
From Maps to Apps the Future of Drone TechnologyFrom Maps to Apps the Future of Drone Technology
From Maps to Apps the Future of Drone Technology
Godfrey Nolan
 
Bulletproof
BulletproofBulletproof
Bulletproof
Godfrey Nolan
 
Attacking android insecurity
Attacking android insecurityAttacking android insecurity
Attacking android insecurity
Godfrey Nolan
 
Automotive android
Automotive androidAutomotive android
Automotive android
Godfrey Nolan
 
Design Patterns every Android developer should know
Design Patterns every Android developer should knowDesign Patterns every Android developer should know
Design Patterns every Android developer should know
muratcanbur
 
SuperSites
SuperSitesSuperSites
SuperSites
TERN Australia
 
IP-guard Catalog
IP-guard CatalogIP-guard Catalog
IP-guard Catalog
IP-guard Sys Help Solutions
 
Curriculum de Juan Carlos Sánchez Illán
Curriculum de Juan Carlos Sánchez IllánCurriculum de Juan Carlos Sánchez Illán
Curriculum de Juan Carlos Sánchez Illán
Juan Carlos Sanchéz Illán
 
Streams Studio Support for IBM InfoSphere Streams V4.0
Streams Studio Support for IBM InfoSphere Streams V4.0Streams Studio Support for IBM InfoSphere Streams V4.0
Streams Studio Support for IBM InfoSphere Streams V4.0
lisanl
 
Maria jose naranjo
Maria jose naranjoMaria jose naranjo
Maria jose naranjo
mariajosenaranjo_11
 
Bondia.cat 05/11/2013
Bondia.cat 05/11/2013Bondia.cat 05/11/2013
Bondia.cat 05/11/2013
Bondia Lleida Sl
 
LA CRÓNICA 617
LA CRÓNICA 617LA CRÓNICA 617
LA CRÓNICA 617
La Crónica Comarca de Antequera
 
Java/Scala Lab: Игорь Вахромеев - Parallel your process with Spring Batch
Java/Scala Lab: Игорь Вахромеев - Parallel your process with Spring BatchJava/Scala Lab: Игорь Вахромеев - Parallel your process with Spring Batch
Java/Scala Lab: Игорь Вахромеев - Parallel your process with Spring Batch
GeeksLab Odessa
 
Estaciones de climatización, Herramientas y Accesorios #TerritorioHELLA
Estaciones de climatización, Herramientas y Accesorios #TerritorioHELLAEstaciones de climatización, Herramientas y Accesorios #TerritorioHELLA
Estaciones de climatización, Herramientas y Accesorios #TerritorioHELLA
HELLA Spain
 
Catalog Avon - Campania 05 / 2011 - avonstore
Catalog Avon - Campania 05 / 2011 - avonstoreCatalog Avon - Campania 05 / 2011 - avonstore
Catalog Avon - Campania 05 / 2011 - avonstore
Vecina_ro
 
Manual de tecnicas radiologicas de bolso
Manual de tecnicas radiologicas de bolsoManual de tecnicas radiologicas de bolso
Manual de tecnicas radiologicas de bolso
Ademar Ribeiro
 
Controlling diseases to ensure better animal health
Controlling diseases to ensure better animal healthControlling diseases to ensure better animal health
Controlling diseases to ensure better animal health
Deepa Menon
 
TEMA 19 lA ARQUITECTURA DEL S.XX
TEMA 19 lA ARQUITECTURA DEL S.XXTEMA 19 lA ARQUITECTURA DEL S.XX
TEMA 19 lA ARQUITECTURA DEL S.XX
@evasociales
 
From Maps to Apps the Future of Drone Technology
From Maps to Apps the Future of Drone TechnologyFrom Maps to Apps the Future of Drone Technology
From Maps to Apps the Future of Drone Technology
Godfrey Nolan
 
Attacking android insecurity
Attacking android insecurityAttacking android insecurity
Attacking android insecurity
Godfrey Nolan
 
Design Patterns every Android developer should know
Design Patterns every Android developer should knowDesign Patterns every Android developer should know
Design Patterns every Android developer should know
muratcanbur
 
Streams Studio Support for IBM InfoSphere Streams V4.0
Streams Studio Support for IBM InfoSphere Streams V4.0Streams Studio Support for IBM InfoSphere Streams V4.0
Streams Studio Support for IBM InfoSphere Streams V4.0
lisanl
 
Java/Scala Lab: Игорь Вахромеев - Parallel your process with Spring Batch
Java/Scala Lab: Игорь Вахромеев - Parallel your process with Spring BatchJava/Scala Lab: Игорь Вахромеев - Parallel your process with Spring Batch
Java/Scala Lab: Игорь Вахромеев - Parallel your process with Spring Batch
GeeksLab Odessa
 
Estaciones de climatización, Herramientas y Accesorios #TerritorioHELLA
Estaciones de climatización, Herramientas y Accesorios #TerritorioHELLAEstaciones de climatización, Herramientas y Accesorios #TerritorioHELLA
Estaciones de climatización, Herramientas y Accesorios #TerritorioHELLA
HELLA Spain
 
Catalog Avon - Campania 05 / 2011 - avonstore
Catalog Avon - Campania 05 / 2011 - avonstoreCatalog Avon - Campania 05 / 2011 - avonstore
Catalog Avon - Campania 05 / 2011 - avonstore
Vecina_ro
 
Manual de tecnicas radiologicas de bolso
Manual de tecnicas radiologicas de bolsoManual de tecnicas radiologicas de bolso
Manual de tecnicas radiologicas de bolso
Ademar Ribeiro
 
Controlling diseases to ensure better animal health
Controlling diseases to ensure better animal healthControlling diseases to ensure better animal health
Controlling diseases to ensure better animal health
Deepa Menon
 
TEMA 19 lA ARQUITECTURA DEL S.XX
TEMA 19 lA ARQUITECTURA DEL S.XXTEMA 19 lA ARQUITECTURA DEL S.XX
TEMA 19 lA ARQUITECTURA DEL S.XX
@evasociales
 
Ad

Similar to Android Design Patterns (20)

Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
DataArt
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
Daniel Baccin
 
Android crashcourse
Android crashcourseAndroid crashcourse
Android crashcourse
Alexey Buzdin
 
Introduction to Spring Boot.pdf
Introduction to Spring Boot.pdfIntroduction to Spring Boot.pdf
Introduction to Spring Boot.pdf
ShaiAlmog1
 
Action bar
Action barAction bar
Action bar
Mu Chun Wang
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
Yekmer Simsek
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
CodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPigCodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPig
Dusan Zamurovic
 
Android workshop
Android workshopAndroid workshop
Android workshop
Michael Galpin
 
Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017
Elyse Kolker Gordon
 
Android TV: Building apps with Google’s Leanback Library
Android TV: Building apps with  Google’s Leanback LibraryAndroid TV: Building apps with  Google’s Leanback Library
Android TV: Building apps with Google’s Leanback Library
Joe Birch
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
Darwin Durand
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
habib_786
 
Test
TestTest
Test
fshimao
 
Your Second iPhone App - Code Listings
Your Second iPhone App - Code ListingsYour Second iPhone App - Code Listings
Your Second iPhone App - Code Listings
Vu Tran Lam
 
Why SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScriptWhy SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScript
martinlippert
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
Ali Parmaksiz
 
Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)
Fafadia Tech
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in Android
Robert Cooper
 
Cours Authentification FireBase Sign/Sign Up
Cours Authentification FireBase Sign/Sign UpCours Authentification FireBase Sign/Sign Up
Cours Authentification FireBase Sign/Sign Up
amar719595
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
DataArt
 
Saindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender androidSaindo da zona de conforto… resolvi aprender android
Saindo da zona de conforto… resolvi aprender android
Daniel Baccin
 
Introduction to Spring Boot.pdf
Introduction to Spring Boot.pdfIntroduction to Spring Boot.pdf
Introduction to Spring Boot.pdf
ShaiAlmog1
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
Yekmer Simsek
 
CodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPigCodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPig
Dusan Zamurovic
 
Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017
Elyse Kolker Gordon
 
Android TV: Building apps with Google’s Leanback Library
Android TV: Building apps with  Google’s Leanback LibraryAndroid TV: Building apps with  Google’s Leanback Library
Android TV: Building apps with Google’s Leanback Library
Joe Birch
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
Darwin Durand
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
habib_786
 
Your Second iPhone App - Code Listings
Your Second iPhone App - Code ListingsYour Second iPhone App - Code Listings
Your Second iPhone App - Code Listings
Vu Tran Lam
 
Why SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScriptWhy SOLID matters - even for JavaScript
Why SOLID matters - even for JavaScript
martinlippert
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
Ali Parmaksiz
 
Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)
Fafadia Tech
 
What's New in Android
What's New in AndroidWhat's New in Android
What's New in Android
Robert Cooper
 
Cours Authentification FireBase Sign/Sign Up
Cours Authentification FireBase Sign/Sign UpCours Authentification FireBase Sign/Sign Up
Cours Authentification FireBase Sign/Sign Up
amar719595
 
Ad

More from Godfrey Nolan (20)

Counting Cars with Drones
Counting Cars with DronesCounting Cars with Drones
Counting Cars with Drones
Godfrey Nolan
 
Customising QGroundControl
Customising QGroundControlCustomising QGroundControl
Customising QGroundControl
Godfrey Nolan
 
DJI Payload SDK
DJI Payload SDKDJI Payload SDK
DJI Payload SDK
Godfrey Nolan
 
Parrot Tutorials in Kotlin
Parrot Tutorials in KotlinParrot Tutorials in Kotlin
Parrot Tutorials in Kotlin
Godfrey Nolan
 
DJI Mobile SDK Tutorials in kotlin
DJI Mobile SDK Tutorials in kotlinDJI Mobile SDK Tutorials in kotlin
DJI Mobile SDK Tutorials in kotlin
Godfrey Nolan
 
Drone sdk showdown
Drone sdk showdownDrone sdk showdown
Drone sdk showdown
Godfrey Nolan
 
AI/ML in drones
AI/ML in dronesAI/ML in drones
AI/ML in drones
Godfrey Nolan
 
Getting started with tensor flow datasets
Getting started with tensor flow datasets Getting started with tensor flow datasets
Getting started with tensor flow datasets
Godfrey Nolan
 
Using ML to make your UI tests more robust
Using ML to make your UI tests more robustUsing ML to make your UI tests more robust
Using ML to make your UI tests more robust
Godfrey Nolan
 
Java best practices
Java best practicesJava best practices
Java best practices
Godfrey Nolan
 
Counting sheep with Drones and AI
Counting sheep with Drones and AICounting sheep with Drones and AI
Counting sheep with Drones and AI
Godfrey Nolan
 
Writing Secure Mobile Apps for Drones
Writing Secure Mobile Apps for DronesWriting Secure Mobile Apps for Drones
Writing Secure Mobile Apps for Drones
Godfrey Nolan
 
Android Device Labs
Android Device LabsAndroid Device Labs
Android Device Labs
Godfrey Nolan
 
The Day We Infected Ourselves with Ransomware
The Day We Infected Ourselves with RansomwareThe Day We Infected Ourselves with Ransomware
The Day We Infected Ourselves with Ransomware
Godfrey Nolan
 
Agile Android
Agile AndroidAgile Android
Agile Android
Godfrey Nolan
 
Agile Swift
Agile SwiftAgile Swift
Agile Swift
Godfrey Nolan
 
Android Refactoring
Android RefactoringAndroid Refactoring
Android Refactoring
Godfrey Nolan
 
Agile mobile
Agile mobileAgile mobile
Agile mobile
Godfrey Nolan
 
Tableau 10 and quickbooks
Tableau 10 and quickbooksTableau 10 and quickbooks
Tableau 10 and quickbooks
Godfrey Nolan
 
Network graphs in tableau
Network graphs in tableauNetwork graphs in tableau
Network graphs in tableau
Godfrey Nolan
 
Counting Cars with Drones
Counting Cars with DronesCounting Cars with Drones
Counting Cars with Drones
Godfrey Nolan
 
Customising QGroundControl
Customising QGroundControlCustomising QGroundControl
Customising QGroundControl
Godfrey Nolan
 
Parrot Tutorials in Kotlin
Parrot Tutorials in KotlinParrot Tutorials in Kotlin
Parrot Tutorials in Kotlin
Godfrey Nolan
 
DJI Mobile SDK Tutorials in kotlin
DJI Mobile SDK Tutorials in kotlinDJI Mobile SDK Tutorials in kotlin
DJI Mobile SDK Tutorials in kotlin
Godfrey Nolan
 
Getting started with tensor flow datasets
Getting started with tensor flow datasets Getting started with tensor flow datasets
Getting started with tensor flow datasets
Godfrey Nolan
 
Using ML to make your UI tests more robust
Using ML to make your UI tests more robustUsing ML to make your UI tests more robust
Using ML to make your UI tests more robust
Godfrey Nolan
 
Counting sheep with Drones and AI
Counting sheep with Drones and AICounting sheep with Drones and AI
Counting sheep with Drones and AI
Godfrey Nolan
 
Writing Secure Mobile Apps for Drones
Writing Secure Mobile Apps for DronesWriting Secure Mobile Apps for Drones
Writing Secure Mobile Apps for Drones
Godfrey Nolan
 
The Day We Infected Ourselves with Ransomware
The Day We Infected Ourselves with RansomwareThe Day We Infected Ourselves with Ransomware
The Day We Infected Ourselves with Ransomware
Godfrey Nolan
 
Tableau 10 and quickbooks
Tableau 10 and quickbooksTableau 10 and quickbooks
Tableau 10 and quickbooks
Godfrey Nolan
 
Network graphs in tableau
Network graphs in tableauNetwork graphs in tableau
Network graphs in tableau
Godfrey Nolan
 

Recently uploaded (19)

highend-srxseries-services-gateways-customer-presentation.pptx
highend-srxseries-services-gateways-customer-presentation.pptxhighend-srxseries-services-gateways-customer-presentation.pptx
highend-srxseries-services-gateways-customer-presentation.pptx
elhadjcheikhdiop
 
White and Red Clean Car Business Pitch Presentation.pptx
White and Red Clean Car Business Pitch Presentation.pptxWhite and Red Clean Car Business Pitch Presentation.pptx
White and Red Clean Car Business Pitch Presentation.pptx
canumatown
 
Best web hosting Vancouver 2025 for you business
Best web hosting Vancouver 2025 for you businessBest web hosting Vancouver 2025 for you business
Best web hosting Vancouver 2025 for you business
steve198109
 
Mobile database for your company telemarketing or sms marketing campaigns. Fr...
Mobile database for your company telemarketing or sms marketing campaigns. Fr...Mobile database for your company telemarketing or sms marketing campaigns. Fr...
Mobile database for your company telemarketing or sms marketing campaigns. Fr...
DataProvider1
 
Top Vancouver Green Business Ideas for 2025 Powered by 4GoodHosting
Top Vancouver Green Business Ideas for 2025 Powered by 4GoodHostingTop Vancouver Green Business Ideas for 2025 Powered by 4GoodHosting
Top Vancouver Green Business Ideas for 2025 Powered by 4GoodHosting
steve198109
 
Perguntas dos animais - Slides ilustrados de múltipla escolha
Perguntas dos animais - Slides ilustrados de múltipla escolhaPerguntas dos animais - Slides ilustrados de múltipla escolha
Perguntas dos animais - Slides ilustrados de múltipla escolha
socaslev
 
(Hosting PHising Sites) for Cryptography and network security
(Hosting PHising Sites) for Cryptography and network security(Hosting PHising Sites) for Cryptography and network security
(Hosting PHising Sites) for Cryptography and network security
aluacharya169
 
Smart Mobile App Pitch Deck丨AI Travel App Presentation Template
Smart Mobile App Pitch Deck丨AI Travel App Presentation TemplateSmart Mobile App Pitch Deck丨AI Travel App Presentation Template
Smart Mobile App Pitch Deck丨AI Travel App Presentation Template
yojeari421237
 
Reliable Vancouver Web Hosting with Local Servers & 24/7 Support
Reliable Vancouver Web Hosting with Local Servers & 24/7 SupportReliable Vancouver Web Hosting with Local Servers & 24/7 Support
Reliable Vancouver Web Hosting with Local Servers & 24/7 Support
steve198109
 
IT Services Workflow From Request to Resolution
IT Services Workflow From Request to ResolutionIT Services Workflow From Request to Resolution
IT Services Workflow From Request to Resolution
mzmziiskd
 
DNS Resolvers and Nameservers (in New Zealand)
DNS Resolvers and Nameservers (in New Zealand)DNS Resolvers and Nameservers (in New Zealand)
DNS Resolvers and Nameservers (in New Zealand)
APNIC
 
OSI TCP IP Protocol Layers description f
OSI TCP IP Protocol Layers description fOSI TCP IP Protocol Layers description f
OSI TCP IP Protocol Layers description f
cbr49917
 
APNIC Update, presented at NZNOG 2025 by Terry Sweetser
APNIC Update, presented at NZNOG 2025 by Terry SweetserAPNIC Update, presented at NZNOG 2025 by Terry Sweetser
APNIC Update, presented at NZNOG 2025 by Terry Sweetser
APNIC
 
APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025
APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025
APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025
APNIC
 
project_based_laaaaaaaaaaearning,kelompok 10.pptx
project_based_laaaaaaaaaaearning,kelompok 10.pptxproject_based_laaaaaaaaaaearning,kelompok 10.pptx
project_based_laaaaaaaaaaearning,kelompok 10.pptx
redzuriel13
 
Determining Glass is mechanical textile
Determining  Glass is mechanical textileDetermining  Glass is mechanical textile
Determining Glass is mechanical textile
Azizul Hakim
 
Computers Networks Computers Networks Computers Networks
Computers Networks Computers Networks Computers NetworksComputers Networks Computers Networks Computers Networks
Computers Networks Computers Networks Computers Networks
Tito208863
 
Understanding the Tor Network and Exploring the Deep Web
Understanding the Tor Network and Exploring the Deep WebUnderstanding the Tor Network and Exploring the Deep Web
Understanding the Tor Network and Exploring the Deep Web
nabilajabin35
 
5-Proses-proses Akuisisi Citra Digital.pptx
5-Proses-proses Akuisisi Citra Digital.pptx5-Proses-proses Akuisisi Citra Digital.pptx
5-Proses-proses Akuisisi Citra Digital.pptx
andani26
 
highend-srxseries-services-gateways-customer-presentation.pptx
highend-srxseries-services-gateways-customer-presentation.pptxhighend-srxseries-services-gateways-customer-presentation.pptx
highend-srxseries-services-gateways-customer-presentation.pptx
elhadjcheikhdiop
 
White and Red Clean Car Business Pitch Presentation.pptx
White and Red Clean Car Business Pitch Presentation.pptxWhite and Red Clean Car Business Pitch Presentation.pptx
White and Red Clean Car Business Pitch Presentation.pptx
canumatown
 
Best web hosting Vancouver 2025 for you business
Best web hosting Vancouver 2025 for you businessBest web hosting Vancouver 2025 for you business
Best web hosting Vancouver 2025 for you business
steve198109
 
Mobile database for your company telemarketing or sms marketing campaigns. Fr...
Mobile database for your company telemarketing or sms marketing campaigns. Fr...Mobile database for your company telemarketing or sms marketing campaigns. Fr...
Mobile database for your company telemarketing or sms marketing campaigns. Fr...
DataProvider1
 
Top Vancouver Green Business Ideas for 2025 Powered by 4GoodHosting
Top Vancouver Green Business Ideas for 2025 Powered by 4GoodHostingTop Vancouver Green Business Ideas for 2025 Powered by 4GoodHosting
Top Vancouver Green Business Ideas for 2025 Powered by 4GoodHosting
steve198109
 
Perguntas dos animais - Slides ilustrados de múltipla escolha
Perguntas dos animais - Slides ilustrados de múltipla escolhaPerguntas dos animais - Slides ilustrados de múltipla escolha
Perguntas dos animais - Slides ilustrados de múltipla escolha
socaslev
 
(Hosting PHising Sites) for Cryptography and network security
(Hosting PHising Sites) for Cryptography and network security(Hosting PHising Sites) for Cryptography and network security
(Hosting PHising Sites) for Cryptography and network security
aluacharya169
 
Smart Mobile App Pitch Deck丨AI Travel App Presentation Template
Smart Mobile App Pitch Deck丨AI Travel App Presentation TemplateSmart Mobile App Pitch Deck丨AI Travel App Presentation Template
Smart Mobile App Pitch Deck丨AI Travel App Presentation Template
yojeari421237
 
Reliable Vancouver Web Hosting with Local Servers & 24/7 Support
Reliable Vancouver Web Hosting with Local Servers & 24/7 SupportReliable Vancouver Web Hosting with Local Servers & 24/7 Support
Reliable Vancouver Web Hosting with Local Servers & 24/7 Support
steve198109
 
IT Services Workflow From Request to Resolution
IT Services Workflow From Request to ResolutionIT Services Workflow From Request to Resolution
IT Services Workflow From Request to Resolution
mzmziiskd
 
DNS Resolvers and Nameservers (in New Zealand)
DNS Resolvers and Nameservers (in New Zealand)DNS Resolvers and Nameservers (in New Zealand)
DNS Resolvers and Nameservers (in New Zealand)
APNIC
 
OSI TCP IP Protocol Layers description f
OSI TCP IP Protocol Layers description fOSI TCP IP Protocol Layers description f
OSI TCP IP Protocol Layers description f
cbr49917
 
APNIC Update, presented at NZNOG 2025 by Terry Sweetser
APNIC Update, presented at NZNOG 2025 by Terry SweetserAPNIC Update, presented at NZNOG 2025 by Terry Sweetser
APNIC Update, presented at NZNOG 2025 by Terry Sweetser
APNIC
 
APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025
APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025
APNIC -Policy Development Process, presented at Local APIGA Taiwan 2025
APNIC
 
project_based_laaaaaaaaaaearning,kelompok 10.pptx
project_based_laaaaaaaaaaearning,kelompok 10.pptxproject_based_laaaaaaaaaaearning,kelompok 10.pptx
project_based_laaaaaaaaaaearning,kelompok 10.pptx
redzuriel13
 
Determining Glass is mechanical textile
Determining  Glass is mechanical textileDetermining  Glass is mechanical textile
Determining Glass is mechanical textile
Azizul Hakim
 
Computers Networks Computers Networks Computers Networks
Computers Networks Computers Networks Computers NetworksComputers Networks Computers Networks Computers Networks
Computers Networks Computers Networks Computers Networks
Tito208863
 
Understanding the Tor Network and Exploring the Deep Web
Understanding the Tor Network and Exploring the Deep WebUnderstanding the Tor Network and Exploring the Deep Web
Understanding the Tor Network and Exploring the Deep Web
nabilajabin35
 
5-Proses-proses Akuisisi Citra Digital.pptx
5-Proses-proses Akuisisi Citra Digital.pptx5-Proses-proses Akuisisi Citra Digital.pptx
5-Proses-proses Akuisisi Citra Digital.pptx
andani26
 

Android Design Patterns

  • 2. Android Application Architecture (Android Dev Summit) https://www.youtube.com/watch?v=BlkJzgjzL0c
  • 3. What is Your Goal? Scalable Maintainable Testing
  • 4. What is Your Goal? Scalable Add new features quickly Maintainable No spaghetti code Don't cross the streams Testing Easy to mock
  • 5. Why? Easier to add new features Easier to understand Easier to police Make our life easier Make Unit Testing easier
  • 6. How do we get there? https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
  • 11. package alexandria.israelferrer.com.libraryofalexandria; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.widget.BaseAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.RatingBar; import android.widget.TextView; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.squareup.picasso.Picasso; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; public class MainActivity extends Activity { private static final String PACKAGE = "com.israelferrer.alexandria"; private static final String KEY_FAVS = PACKAGE + ".FAVS"; private List<ArtWork> artWorkList; private ArtWorkAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.listView); InputStream stream = getResources().openRawResource(R.raw.artwork); Type listType = new TypeToken<List<ArtWork>>() { }.getType(); artWorkList = new Gson().fromJson(new InputStreamReader(stream), listType); final SharedPreferences preferences = getSharedPreferences(getPackageName() , Context.MODE_PRIVATE); for (ArtWork artWork : artWorkList) { artWork.setRating(preferences.getFloat(PACKAGE + artWork.getId(), 0F)); } adapter = new ArtWorkAdapter(); listView.setAdapter(adapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.filter) { adapter.orderMode(); return true; } return super.onOptionsItemSelected(item); } private class ArtWorkAdapter extends BaseAdapter { private boolean isOrder; private final List<ArtWork> orderedList; public ArtWorkAdapter() { super(); orderedList = new LinkedList<ArtWork>(); } @Override public int getCount() { return artWorkList.size(); } @Override public Object getItem(int position) { return artWorkList.get(position); } @Override public long getItemId(int position) { return Long.valueOf(artWorkList.get(position).getId()); } public void orderMode() { isOrder = !isOrder; if (isOrder) { orderedList.clear(); orderedList.addAll(artWorkList); Collections.sort(orderedList); notifyDataSetChanged(); } else { notifyDataSetChanged(); } } @Override public View getView(int position, View convertView, ViewGroup parent) { final ArtWork artWork; if (isOrder) { artWork = orderedList.get(position); } else { artWork = artWorkList.get(position); } View row; switch (artWork.getType()) { case ArtWork.QUOTE: row = getLayoutInflater().inflate(R.layout.text_row, null); TextView quote = (TextView) row.findViewById(R.id.quote); TextView author = (TextView) row.findViewById(R.id.author); quote.setText(""" + artWork.getText() + """); author.setText(artWork.getAuthor()); break; case ArtWork.PAINTING: final SharedPreferences preferences = getSharedPreferences(getPackageName() , Context.MODE_PRIVATE); final HashSet<String> favs = (HashSet<String>) preferences .getStringSet(KEY_FAVS, new HashSet<String>()); row = getLayoutInflater().inflate(R.layout.painting_row, null); ImageView image = (ImageView) row.findViewById(R.id.painting); TextView painter = (TextView) row.findViewById(R.id.author); painter.setText(artWork.getTitle() + " by " + artWork.getAuthor()); Picasso.with(MainActivity.this).load(artWork.getContentUrl()).fit() .into(image); RatingBar rating = (RatingBar) row.findViewById(R.id.rate); rating.setRating(artWork.getRating()); rating.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() { @Override public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) { preferences.edit().putFloat(PACKAGE + artWork.getId(), rating).apply(); artWork.setRating(rating); } }); CheckBox fav = (CheckBox) row.findViewById(R.id.fav); fav.setChecked(favs.contains(artWork.getId())); fav.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { final HashSet<String> favs = new HashSet<String>((HashSet<String>) preferences .getStringSet(KEY_FAVS, new HashSet<String>())); if (isChecked) { favs.add(artWork.getId()); } else { favs.remove(artWork.getId()); } preferences.edit().putStringSet(KEY_FAVS, favs).apply(); } }); break; case ArtWork.MOVIE: case ArtWork.OPERA: row = new ViewStub(MainActivity.this); break; default: row = getLayoutInflater().inflate(R.layout.text_row, null); } return row; } } }
  • 12. Classic Android Pros Better the devil you know Cons Activities and Fragments quickly become large Painful to make changes or add new features All the logic in Activities, unit testing is impossible Classic Android is not MVC
  • 16. package com.androidexample.mvc; //imports public class FirstScreen extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.firstscreen); final LinearLayout lm = (LinearLayout) findViewById(R.id.linearMain); final Button secondBtn = (Button) findViewById(R.id.second); //Get Global Controller Class object (see application tag in AndroidManifest.xml) final Controller aController = (Controller) getApplicationContext(); /* ........ */ //Product arraylist size int ProductsSize = aController.getProductsArraylistSize(); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); /******** Dynamically create view elements - Start **********/ for(int j=0;j< ProductsSize;j++) { // Get probuct data from product data arraylist String pName = aController.getProducts(j).getProductName(); int pPrice = aController.getProducts(j).getProductPrice(); // Create LinearLayout to view elemnts LinearLayout ll = new LinearLayout(this); ll.setOrientation(LinearLayout.HORIZONTAL); TextView product = new TextView(this); product.setText(" "+pName+" "); //Add textView to LinearLayout ll.addView(product); TextView price = new TextView(this); price.setText(" $"+pPrice+" "); //Add textView to LinearLayout ll.addView(price); final Button btn = new Button(this); btn.setId(j+1); btn.setText("Add To Cart"); // set the layoutParams on the button btn.setLayoutParams(params);
  • 17. package com.androidexample.mvc; import java.util.ArrayList; import android.app.Application; public class Controller extends Application{ private ArrayList<ModelProducts> myProducts = new ArrayList<ModelProducts>(); private ModelCart myCart = new ModelCart(); public ModelProducts getProducts(int pPosition) { return myProducts.get(pPosition); } public void setProducts(ModelProducts Products) { myProducts.add(Products); } public ModelCart getCart() { return myCart; } public int getProductsArraylistSize() { return myProducts.size(); } } package com.androidexample.mvc; public class ModelProducts { private String productName; private String productDesc; private int productPrice; public ModelProducts(String productName,String productDesc,int productPrice) { this.productName = productName; this.productDesc = productDesc; this.productPrice = productPrice; } public String getProductName() { return productName; } public String getProductDesc() { return productDesc; } public int getProductPrice() { return productPrice; } }
  • 19. MVC Pros No business logic in UI Easier to unit test Cons Doesn't scale, separates UI but not model Controller often grows too big
  • 23. MVP Increases separation of concerns into 3 layers Passive View - Render logic Presenter - Handle User events (Proxy) Model - Business logic
  • 27. public interface ArtistsMvpView extends MvpView{ void showLoading(); void hideLoading(); void showArtistNotFoundMessage(); void showConnectionErrorMessage(); void renderArtists(List<Artist> artists); void launchArtistDetail(Artist artist); } public class ArtistsPresenter implements Presenter<ArtistsMvpView>, ArtistCallback { private ArtistsMvpView artistsMvpView; private ArtistsInteractor artistsInteractor; public ArtistsPresenter() { } @Override public void setView(ArtistsMvpView view) { if (view == null) throw new IllegalArgumentException("You can't set a null view"); artistsMvpView = view; artistsInteractor = new ArtistsInteractor(artistsMvpView.getContext()); } @Override public void detachView() { artistsMvpView = null; } public void onSearchArtist(String string) { artistsMvpView.showLoading(); artistsInteractor.loadDataFromApi(string, this); } public void launchArtistDetail(Artist artist) { artistsMvpView.launchArtistDetail(artist); } //..... } public class ArtistsInteractor { SpotifyService mSpotifyService; SpotifyApp mSpotifyApp; public ArtistsInteractor(Context context) { this.mSpotifyApp = SpotifyApp.get(context); this.mSpotifyService = mSpotifyApp.getSpotifyService(); } public void loadDataFromApi(String query, ArtistCallback artistCallback) { mSpotifyService.searchArtist(query) .subscribeOn(mSpotifyApp.SubscribeScheduler()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(artistsSearch -> onSuccess(artistsSearch, artistCallback), throwable -> onError(throwable, artistCallback)); }
  • 29. public class MainActivity extends Activity implements MainView, AdapterView.OnItemClickListener { private ListView listView; private ProgressBar progressBar; private MainPresenter presenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.list); listView.setOnItemClickListener(this); progressBar = (ProgressBar) findViewById(R.id.progress); presenter = new MainPresenterImpl(this); } @Override public void setItems(List<String> items) { listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items)); } @Override public void showMessage(String message) { Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { presenter.onItemClicked(position); } } package com.antonioleiva.mvpexample.app.main; public interface MainPresenter { void onResume(); void onItemClicked(int position); void onDestroy(); } public class MainPresenterImpl implements MainPresenter, FindItemsInteractor.OnFinishedListener { private MainView mainView; private FindItemsInteractor findItemsInteractor; public MainPresenterImpl(MainView mainView) { this.mainView = mainView; findItemsInteractor = new FindItemsInteractorImpl(); } @Override public void onResume() { if (mainView != null) { mainView.showProgress(); } findItemsInteractor.findItems(this); } @Override public void onItemClicked(int position) { if (mainView != null) { mainView.showMessage(String.format("Position %d clicked", position + 1)); } } @Override public void onDestroy() { mainView = null; } @Override public void onFinished(List<String> items) { if (mainView != null) { mainView.setItems(items); mainView.hideProgress(); } } } public interface MainView { void showProgress(); void hideProgress(); void setItems(List<String> items); void showMessage(String message); } http://antonioleiva.com/mvp-android/
  • 30. MVP Testing View Test render logic and interaction with presenter, mock Presenter. Presenter Test that view events invoke the right model method. Mock both View and Model. Model Test the business logic, mock the data source and Presenter.
  • 31. MVP Pros Complex Tasks split into simpler tasks Smaller objects, less bugs, easier to debug Testable Cons BoilerPlate to wire the layers. Model can’t be reused, tied to specific use case. View and Presenter are tied to data objects since they share the same type of object with the Model. https://speakerdeck.com/rallat/androiddevlikeaprodroidconsf
  • 32. MVVM Microsoft Pattern Removes UI code from Activities/Fragments View has no knowledge of model Data Binding = Bind ViewModel to Layout Goodbye Presenter, hello ViewModel
  • 35. <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/password_block" android:id="@+id/email_block" android:visibility="@{data.emailBlockVisibility}"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Email:" android:minWidth="100dp"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="textEmailAddress" android:ems="10" android:id="@+id/email"/> </LinearLayout> @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_main, container, false); mBinding = FragmentMainBinding.bind(view); mViewModel = new MainModel(this, getResources()); mBinding.setData(mViewModel); attachButtonListener(); return view; } public void updateDependentViews() { if (isExistingUserChecked.get()) { emailBlockVisibility.set(View.GONE); loginOrCreateButtonText.set(mResources.getString(R.string.log_in)); } else { emailBlockVisibility.set(View.VISIBLE); loginOrCreateButtonText.set(mResources.getString(R.string.create_user)); } } http://tech.vg.no/2015/07/17/android-databinding-goodbye-presenter-hello-viewmodel/
  • 36. MVVM Pros First Party Library Compile time checking Presentation layer in XML Testable Less code, no more Butterknife Cons Data Binding isn't always appropriate Android Studio integration was flaky
  • 37. Reactive - RxJava Not really an architecture Used in many other architectures Event based Publish / Subscribe
  • 38. public void doLargeComputation( final IComputationListener listener, final OtherParams params) { Subscription subscription = doLargeComputationCall(params) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<List<Result>>>() { @Override public void onNext(final List<Result> results) { listener.doLargeComputationComplete(results); } @Override public void onCompleted() {} @Override public void onError(final Throwable t) { listener.doLargeComputationFailed(t); } } ); } private Observable<List<Result>> doLargeComputationCall(final OtherParams params) { return Observable.defer(new Func0<Observable<List<Result>>>() { @Override public Observable<List<Result>> call() { List<Result> results = doTheRealLargeComputation(params); if (results != null && 0 < results.size()) { return Observable.just(results); } return Observable.error(new ComputationException("Could not do the large computation")); } } ); }
  • 40. Clean Architecture Uncle Bob Much better decoupling, better reusabiity Lots more layers
  • 42. Clean Architecture is... Independent of Frameworks Testable Independent of UI Independent of Database Independent of any External Agency Decoupled
  • 47. tearDown() Act Early Trust but Verify Know what you're getting into YAGNI
  • 48. Repos MVC: http://androidexample.com/Use_MVC_Pattern_To_Create_Very_Basic_Shopping_Cart__-_Android_Example MVC-Reactive: https://github.com/yigit/dev-summit-architecture-demo MVP: https://github.com/antoniolg/androidmvp MVVM: https://github.com/ivacf/archi Clean: https://github.com/rallat/EffectiveAndroid