SlideShare a Scribd company logo
OMG, The hackathon is coming
https://goo.gl/xZnh1c
Idan Felix
Android
Design Patterns
+
Not this kind of patterns
The term Design Patterns also means UX patterns.
That’s not the kind of the Design Patterns we’ll discuss today.
Goals
Learn the basic why-and-what of Design Patterns
Inspire to learn and use patterns
improve your code-reading skills
improve your code-writing skills
improve your code-communication skills
Agenda
- 2 Truths about software development in the long run
- Worst Feeling
- Code Smells
- Design Patterns Party
- Abstract Server, Observer
- Static Factory Method
- Builder pattern
Warning:
There are many
BIG WORDS
in this session.
Android design patterns
Fact of life
Over time,
New code turns to Old code,
and Old code turns to Legacy code
Read more: https://en.wikipedia.org/wiki/Software_rot
Code Rot, or Code Decay, is the slow deterioration of software.
Code Smells - Symptoms of Bad Design
- Rigidity
- Fragility
- Immobility
- Viscosity
- Needless complexity
- Needless Repetition
Source: Robert C. Martin (Uncle Bob)
- Code is hard to change
- Design is easy to break
- Design is not reusable
- Easier to do the wrong thing
- Design contains useless elements
- Same code appears again and again
Code Smells - Symptoms of Bad Design
- Rigidity
- Fragility
- Immobility
- Viscosity
- Needless complexity
- Needless Repetition
Source: Robert C. Martin (Uncle Bob)
- “Hmm.. That was a lot more complicated than I thought.“
- “X is always on the bug list / we’re afraid to touch it“
- “Yeah, It’s the same, but we have to copy-paste its code“
- “No problem, let’s hack it like … and fix it later“
- “High wtf/min ratio in a public CR“
- “Haven’t I seen this line before? || Ctrl+(C→V)“
Design Patterns
Re-usable form of a solution to a design problem.
Design patterns are great, as they:
- Name common code structures, so we can discuss them
- Time proven solutions, that make code easier to understand
- Fun at Job Interviews
- Really overloaded term
Design Patterns
There are many sources for Design Patterns, but these 4 books are a
great starting point
- Design Patterns (GoF)
- Code Complete (Microsoft)
- Effective Java (Bloch)
- PoEAA (Fowler)
Design Patterns
As with everything, there are a few challenges when choosing which
patterns to use and how:
- Some patterns are Anti-patterns in general,
Some patterns are Anti-patterns on Android.
- Knowing when to use a design pattern,
and knowing which one to choose
Design patterns are like spices.
- Creational Patterns - patterns for creating objects
- Structural Patterns - patterns for classes composition
- Behavioral Patterns - patterns for objects communication
Design Patterns - GoF Classification
What are we going to read
Android is Open Source
so we’re about to look at some patterns and their implementation in
the framework.
You can read the framework’s code here:
https://github.com/android/platform_frameworks_base/tree/master/core/java/android
Design patterns warm-up:
The Abstract Server
Design Pattern
Behavioral patterns
Abstract Server
This is the most basic design pattern,
used to describe a simple OO Principle:
Prefer composition over inheritance
Consider a switch that turns on a lamp:
Switch Lamp
Turns on
+ click() + TurnOn()
+ TurnOff()
+ isOn()
How can we use the
Switch to turn on the
boiler?
How can we Unit Test a
Switch?
Abstract Server
Extract an interface from the
lamp and separate the lamp
and the switch.
You’ll be able to use the same
switch with anything else you
like.
Switch Switchable
Turns on
+ click() + TurnOn()
+ TurnOff()
+ isOn()
Lamp
+ TurnOn()
+ TurnOff()
+ isOn()
extends
You already know this pattern
This is how callbacks are
implemented.
Let’s see the related code.
View
View.OnClick
Listener
invokes
+ performClick + onClick
MainActivity
+ onClick()
implements
View.performClick()
/**
* Call this view's OnClickListener, if it is defined. Performs all normal
* actions associated with clicking: reporting accessibility event, playing
* a sound, etc.
*
* @return True there was an assigned OnClickListener that was called, false
* otherwise is returned.
*/
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
https://github.com/android/platform_frameworks_base/blob/mast
View.OnClickListener
/**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
https://github.com/android/platform_frameworks_base/blob/mast
The Observer Pattern
An extension of the Abstract Server pattern, enables to use many
abstract servers.
Instead of holding a listener
in a single field, hold a collection.
This way, you can add
more than one listener.
https://en.wikipedia.org/wiki/Observer_pattern
Sample (Seen last week)
The ViewTreeObserver is a great example.
It’s an object that can notify you on things that happen on the Views
tree, such as when animation completes, scroll changes, and etc.
ViewTreeObserver - Ton of listener collections
// Recursive listeners use CopyOnWriteArrayList
private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners;
private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners;
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
private CopyOnWriteArrayList<OnEnterAnimationCompleteListener> mOnEnterAnimationCompleteListeners;
// Non-recursive listeners use CopyOnWriteArray
// Any listener invoked from ViewRootImpl.performTraversals() should not be recursive
private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners;
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
ViewTreeObserver - sample registration
public void addOnWindowShownListener(OnWindowShownListener listener) {
checkIsAlive();
if (mOnWindowShownListeners == null) {
mOnWindowShownListeners = new CopyOnWriteArray<OnWindowShownListener>();
}
mOnWindowShownListeners.add(listener);
if (mWindowShown) {
listener.onWindowShown();
}
}
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
ViewTreeObserver - sample invocation
public final void dispatchOnWindowShown() {
mWindowShown = true;
final CopyOnWriteArray<OnWindowShownListener> listeners = mOnWindowShownListeners;
if (listeners != null && listeners.size() > 0) {
CopyOnWriteArray.Access<OnWindowShownListener> access = listeners.start();
try {
int count = access.size();
for (int i = 0; i < count; i++) {
access.get(i).onWindowShown();
}
} finally {
listeners.end();
}
}
}
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
Creational Patterns
Static Factory Method - Flavor 1
Replace a constructor with a static (named) method, and hide the
constructor as private.
This way, the only (sane) way to create such class is via the static
factory method.
Toast.makeText(...)
public class Toast {
// ...
public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
Toast result = new Toast(context);
LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
tv.setText(text);
result.mNextView = v;
result.mDuration = duration;
return result;
}
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
Static Factory Method - Flavor 2
Create a static factory method for stuff your class might need.
public class SomeActivity
public Intent createSomeActivityIntent(int extraInt, String extraString){
// Create an intent, add the extras properly, and return the intent
}
}
The Builder Pattern
Sometimes, creation is more complicated, and you want to create a
DSL for the creation, over creating many different constructors.
This reduces mistakes (10x to code-autocompletion) and improves
code readability and discoverability.
The Builder Pattern
https://en.wikipedia.org/wiki/Builder_pattern
You Are Here
AlertDialog.Builder
public static class Builder {
public Builder setTitle(@StringRes int titleId)
public Builder setTitle(CharSequence title)
public Builder setCustomTitle(View customTitleView)
public Builder setMessage(@StringRes int messageId)
public Builder setIcon(@DrawableRes int iconId)
public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener)
public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener)
public Builder setCancelable(boolean cancelable)
public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener)
public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener)
public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener)
public Builder setView(int layoutResId)
// ...
public AlertDialog create()
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
NotificationCompat.Builder
public static class Builder
public Builder setUsesChronometer(boolean b)
public Builder setSmallIcon(int icon)
public Builder setContentTitle(CharSequence title)
public Builder setContentText(CharSequence text)
public Builder setSubText(CharSequence text)
public Builder setNumber(int number)
public Builder setProgress(int max, int progress, boolean indeterminate)
public Builder setContent(RemoteViews views)
public Builder setDeleteIntent(PendingIntent intent)
public Builder setTicker(CharSequence tickerText)
public Builder setLargeIcon(Bitmap icon)
public Builder setSound(Uri sound)
public Builder setVibrate(long[] pattern)
public Builder setOngoing(boolean ongoing)
public Builder setAutoCancel(boolean autoCancel)
public Builder setPriority(int pri)
// ...
https://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/app/NotificationCompat.java#L869
Bonus Pattern: Fluent Interface (like it’s the 90s)
Create a simple fluent interface, by having all methods return a builder, this builder.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Hackathon Registration");
builder.setMessage("All team members must register TODAY.");
builder.setPositiveButton("OK, I'm registered", null);
builder.setNegativeButton("I'll register today", null);
AlertDialog dialog = builder.create();
vs.
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Hackathon Registration")
.setMessage("All team members must register TODAY.")
.setPositiveButton("OK, I'm registered", null)
.setNegativeButton("I'll register today", null)
.create();
Structural Patterns
Decorator
https://en.wikipedia.org/wiki/Decorator_pattern
an object wrapper, that adds or
changes the functionality.
Demo - Increase in Shekel Tish’im
Meal
Burger
Meal
Shnitzel
Meal
XL
Demo - Increase in Shekel Tish’im
public interface Meal {
double getPrice();
String getChips();
String getMainCourse();
String getDrink();
}
public class BurgerMeal implements Meal {
public double getPrice() { return 10; }
public String getChips() { return "Medium Chips"; }
public String getMainCourse() { return "Burger"; }
public String getDrink() { return "Medium Drink"; }
}
Demo - Increase in Shekel Tish’im
public class XL implements Meal {
private static final double XL_COST = 1.90;
private Meal meal;
public XL(Meal meal) { this.meal = meal; }
public double getPrice() {
double price = meal.getPrice() + XL_COST;
return price;
}
public String getChips() {
return "Extra large chips";
}
}
public String getMainCourse() {
return meal.getMainCourse();
}
public String getDrink() {
return "Extra large drink";
}
Exercise - Layered math problem
We have an interface for getting sets of
integers one at a time, and we have a class
that implements it and provides 1, 2, ..., n,
and code that reads such an IntProvider until it ends with n=3000.
Using decorators, write the first 5
multiples of 7 that are larger than 38,
and stop.
IntProvider
getCurrent : int
moveNext : bool
Credit: Iterator Pattern, Wikipedia
Exercise - Layered math problem
IntProvider
getCurrent : int
moveNext : bool
This is our starting point:
int n = 3000;
IntProvider heartbeat = new IntHeartBeat(n);
IntProvider result = heartbeat;
while (result.moveNext()){
System.out.println(result.getCurrent());
}
Solution - Layered math problem
IntProvider skipped = new MultiplicationsOf(heartbeat, 7);
IntProvider greaterThenThirtyEight =
new
PassGreaterThan(skipped, 38);
IntProvider takeOnlyFive =
new
TakeOnly(greaterThenThirtyEight, 5);
IntProvider result = takeOnlyFive;
Solution - Layered math problem
IntProvider skipped = new MultiplicationsOf(heartbeat, 7);
IntProvider greaterThenThirtyEight =
new
PassGreaterThan(skipped, 38);
IntProvider takeOnlyFive =
new
TakeOnly(greaterThenThirtyEight, 5);
IntProvider result = takeOnlyFive;
7, 14, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ...
42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ...
42, 49, 56, 63, 70 and STOP.
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ...
Where is it found in the framework?
Sample of Scroll View
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child, params);
}
It extends FrameLayout but allows only one child.
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/ScrollView.java
Summary
What did we see
We saw a few Design Patterns
Pattern Description SRC
Abstract Server Adding abstraction to increase reusability Robert C. Martin
Observer Subscribe to things that happen GoF
Static Factory
Method
Invert ownership on creation instructions
Add compile-time safety to Intent’s Extras
Effective Java
Builder Complex building scenario, avoid 2n
constructors
GoF
Decorator Change object’s behavior without changing its
interface, its code and its usages
GoF
Any Questions?

More Related Content

Similar to Android design patterns (20)

PDF
10 Ways To Improve Your Code
ConSanFrancisco123
 
PDF
10 Ways To Improve Your Code( Neal Ford)
guestebde
 
PDF
Tdd is not about testing
Gianluca Padovani
 
PDF
Cucumber meets iPhone
Erin Dees
 
PPTX
Going open source with small teams
Jamie Thomas
 
PPTX
Lecture #3 activities and intents
Vitali Pekelis
 
PDF
Building an Open Source iOS app: lessons learned
Wojciech Koszek
 
PPT
Enterprise PHP (PHP London Conference 2008)
Ivo Jansch
 
PPTX
iOS Development at Scale @Chegg
GalOrlanczyk
 
PDF
AI Intelligence: Exploring the Future of Artificial Intelligence
sayalikerimova20
 
PDF
Hacking the Kinect with GAFFTA Day 1
benDesigning
 
PPTX
Writing clean code in C# and .NET
Dror Helper
 
PDF
Codeception Testing Framework -- English #phpkansai
Florent Batard
 
PPTX
Design patterns
nisheesh
 
PDF
So You Just Inherited a $Legacy Application...
Joe Ferguson
 
PDF
So You Just Inherited a $Legacy Application… NomadPHP July 2016
Joe Ferguson
 
PPT
State ofappdevelopment
gillygize
 
PPTX
Hacktoberfest'24 _ GDG on Campus BU.pptx
nilaygupta3003
 
PPT
Lunch and learn as3_frameworks
Yuri Visser
 
PDF
The Ring programming language version 1.5.4 book - Part 180 of 185
Mahmoud Samir Fayed
 
10 Ways To Improve Your Code
ConSanFrancisco123
 
10 Ways To Improve Your Code( Neal Ford)
guestebde
 
Tdd is not about testing
Gianluca Padovani
 
Cucumber meets iPhone
Erin Dees
 
Going open source with small teams
Jamie Thomas
 
Lecture #3 activities and intents
Vitali Pekelis
 
Building an Open Source iOS app: lessons learned
Wojciech Koszek
 
Enterprise PHP (PHP London Conference 2008)
Ivo Jansch
 
iOS Development at Scale @Chegg
GalOrlanczyk
 
AI Intelligence: Exploring the Future of Artificial Intelligence
sayalikerimova20
 
Hacking the Kinect with GAFFTA Day 1
benDesigning
 
Writing clean code in C# and .NET
Dror Helper
 
Codeception Testing Framework -- English #phpkansai
Florent Batard
 
Design patterns
nisheesh
 
So You Just Inherited a $Legacy Application...
Joe Ferguson
 
So You Just Inherited a $Legacy Application… NomadPHP July 2016
Joe Ferguson
 
State ofappdevelopment
gillygize
 
Hacktoberfest'24 _ GDG on Campus BU.pptx
nilaygupta3003
 
Lunch and learn as3_frameworks
Yuri Visser
 
The Ring programming language version 1.5.4 book - Part 180 of 185
Mahmoud Samir Fayed
 

More from Vitali Pekelis (20)

PDF
Droidkaigi2019thagikura 190208135940
Vitali Pekelis
 
PDF
Droidkaigi 2019
Vitali Pekelis
 
PPTX
Google i o &amp; android q changes 2019
Vitali Pekelis
 
PPTX
Android Q 2019
Vitali Pekelis
 
PPTX
Advanced #6 clean architecture
Vitali Pekelis
 
PPTX
Advanced #4 GPU & Animations
Vitali Pekelis
 
PDF
Advanced #2 networking
Vitali Pekelis
 
PPTX
Advanced #2 threading
Vitali Pekelis
 
PPTX
Advanced #1 cpu, memory
Vitali Pekelis
 
PPTX
All the support you need. Support libs in Android
Vitali Pekelis
 
PPTX
How to build Sdk? Best practices
Vitali Pekelis
 
PPTX
Di &amp; dagger
Vitali Pekelis
 
PPTX
Advanced #3 threading
Vitali Pekelis
 
PPTX
Mobile ui fruit or delicious sweets
Vitali Pekelis
 
PPTX
Lecture #4 c loaders and co.
Vitali Pekelis
 
PPTX
Session #4 b content providers
Vitali Pekelis
 
PPTX
Advanced #2 - ui perf
Vitali Pekelis
 
PDF
Android meetup
Vitali Pekelis
 
PPTX
Android design lecture #3
Vitali Pekelis
 
PPTX
From newbie to ...
Vitali Pekelis
 
Droidkaigi2019thagikura 190208135940
Vitali Pekelis
 
Droidkaigi 2019
Vitali Pekelis
 
Google i o &amp; android q changes 2019
Vitali Pekelis
 
Android Q 2019
Vitali Pekelis
 
Advanced #6 clean architecture
Vitali Pekelis
 
Advanced #4 GPU & Animations
Vitali Pekelis
 
Advanced #2 networking
Vitali Pekelis
 
Advanced #2 threading
Vitali Pekelis
 
Advanced #1 cpu, memory
Vitali Pekelis
 
All the support you need. Support libs in Android
Vitali Pekelis
 
How to build Sdk? Best practices
Vitali Pekelis
 
Di &amp; dagger
Vitali Pekelis
 
Advanced #3 threading
Vitali Pekelis
 
Mobile ui fruit or delicious sweets
Vitali Pekelis
 
Lecture #4 c loaders and co.
Vitali Pekelis
 
Session #4 b content providers
Vitali Pekelis
 
Advanced #2 - ui perf
Vitali Pekelis
 
Android meetup
Vitali Pekelis
 
Android design lecture #3
Vitali Pekelis
 
From newbie to ...
Vitali Pekelis
 
Ad

Recently uploaded (20)

PDF
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
PDF
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
PDF
How to Download and Install ADT (ABAP Development Tools) for Eclipse IDE | SA...
SAP Vista, an A L T Z E N Company
 
PDF
On Software Engineers' Productivity - Beyond Misleading Metrics
Romén Rodríguez-Gil
 
PPTX
Presentation about variables and constant.pptx
kr2589474
 
PPTX
Role Of Python In Programing Language.pptx
jaykoshti048
 
PDF
Protecting the Digital World Cyber Securit
dnthakkar16
 
PDF
Troubleshooting Virtual Threads in Java!
Tier1 app
 
PPTX
Farrell__10e_ch04_PowerPoint.pptx Programming Logic and Design slides
bashnahara11
 
PDF
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
PDF
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
PDF
10 posting ideas for community engagement with AI prompts
Pankaj Taneja
 
PDF
Step-by-Step Guide to Install SAP HANA Studio | Complete Installation Tutoria...
SAP Vista, an A L T Z E N Company
 
PDF
SAP GUI Installation Guide for macOS (iOS) | Connect to SAP Systems on Mac
SAP Vista, an A L T Z E N Company
 
PDF
Virtual Threads in Java: A New Dimension of Scalability and Performance
Tier1 app
 
PPT
Brief History of Python by Learning Python in three hours
adanechb21
 
PPT
Why Reliable Server Maintenance Service in New York is Crucial for Your Business
Sam Vohra
 
PDF
What companies do with Pharo (ESUG 2025)
ESUG
 
PDF
ChatPharo: an Open Architecture for Understanding How to Talk Live to LLMs
ESUG
 
PDF
How Agentic AI Networks are Revolutionizing Collaborative AI Ecosystems in 2025
ronakdubey419
 
Generating Union types w/ Static Analysis
K. Matthew Dupree
 
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
How to Download and Install ADT (ABAP Development Tools) for Eclipse IDE | SA...
SAP Vista, an A L T Z E N Company
 
On Software Engineers' Productivity - Beyond Misleading Metrics
Romén Rodríguez-Gil
 
Presentation about variables and constant.pptx
kr2589474
 
Role Of Python In Programing Language.pptx
jaykoshti048
 
Protecting the Digital World Cyber Securit
dnthakkar16
 
Troubleshooting Virtual Threads in Java!
Tier1 app
 
Farrell__10e_ch04_PowerPoint.pptx Programming Logic and Design slides
bashnahara11
 
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
10 posting ideas for community engagement with AI prompts
Pankaj Taneja
 
Step-by-Step Guide to Install SAP HANA Studio | Complete Installation Tutoria...
SAP Vista, an A L T Z E N Company
 
SAP GUI Installation Guide for macOS (iOS) | Connect to SAP Systems on Mac
SAP Vista, an A L T Z E N Company
 
Virtual Threads in Java: A New Dimension of Scalability and Performance
Tier1 app
 
Brief History of Python by Learning Python in three hours
adanechb21
 
Why Reliable Server Maintenance Service in New York is Crucial for Your Business
Sam Vohra
 
What companies do with Pharo (ESUG 2025)
ESUG
 
ChatPharo: an Open Architecture for Understanding How to Talk Live to LLMs
ESUG
 
How Agentic AI Networks are Revolutionizing Collaborative AI Ecosystems in 2025
ronakdubey419
 
Ad

Android design patterns

  • 1. OMG, The hackathon is coming https://goo.gl/xZnh1c Idan Felix Android Design Patterns +
  • 2. Not this kind of patterns The term Design Patterns also means UX patterns. That’s not the kind of the Design Patterns we’ll discuss today.
  • 3. Goals Learn the basic why-and-what of Design Patterns Inspire to learn and use patterns improve your code-reading skills improve your code-writing skills improve your code-communication skills
  • 4. Agenda - 2 Truths about software development in the long run - Worst Feeling - Code Smells - Design Patterns Party - Abstract Server, Observer - Static Factory Method - Builder pattern
  • 5. Warning: There are many BIG WORDS in this session.
  • 7. Fact of life Over time, New code turns to Old code, and Old code turns to Legacy code
  • 9. Code Smells - Symptoms of Bad Design - Rigidity - Fragility - Immobility - Viscosity - Needless complexity - Needless Repetition Source: Robert C. Martin (Uncle Bob) - Code is hard to change - Design is easy to break - Design is not reusable - Easier to do the wrong thing - Design contains useless elements - Same code appears again and again
  • 10. Code Smells - Symptoms of Bad Design - Rigidity - Fragility - Immobility - Viscosity - Needless complexity - Needless Repetition Source: Robert C. Martin (Uncle Bob) - “Hmm.. That was a lot more complicated than I thought.“ - “X is always on the bug list / we’re afraid to touch it“ - “Yeah, It’s the same, but we have to copy-paste its code“ - “No problem, let’s hack it like … and fix it later“ - “High wtf/min ratio in a public CR“ - “Haven’t I seen this line before? || Ctrl+(C→V)“
  • 11. Design Patterns Re-usable form of a solution to a design problem. Design patterns are great, as they: - Name common code structures, so we can discuss them - Time proven solutions, that make code easier to understand - Fun at Job Interviews - Really overloaded term
  • 12. Design Patterns There are many sources for Design Patterns, but these 4 books are a great starting point - Design Patterns (GoF) - Code Complete (Microsoft) - Effective Java (Bloch) - PoEAA (Fowler)
  • 13. Design Patterns As with everything, there are a few challenges when choosing which patterns to use and how: - Some patterns are Anti-patterns in general, Some patterns are Anti-patterns on Android. - Knowing when to use a design pattern, and knowing which one to choose Design patterns are like spices.
  • 14. - Creational Patterns - patterns for creating objects - Structural Patterns - patterns for classes composition - Behavioral Patterns - patterns for objects communication Design Patterns - GoF Classification
  • 15. What are we going to read Android is Open Source so we’re about to look at some patterns and their implementation in the framework. You can read the framework’s code here: https://github.com/android/platform_frameworks_base/tree/master/core/java/android
  • 16. Design patterns warm-up: The Abstract Server Design Pattern Behavioral patterns
  • 17. Abstract Server This is the most basic design pattern, used to describe a simple OO Principle: Prefer composition over inheritance Consider a switch that turns on a lamp: Switch Lamp Turns on + click() + TurnOn() + TurnOff() + isOn() How can we use the Switch to turn on the boiler? How can we Unit Test a Switch?
  • 18. Abstract Server Extract an interface from the lamp and separate the lamp and the switch. You’ll be able to use the same switch with anything else you like. Switch Switchable Turns on + click() + TurnOn() + TurnOff() + isOn() Lamp + TurnOn() + TurnOff() + isOn() extends
  • 19. You already know this pattern This is how callbacks are implemented. Let’s see the related code. View View.OnClick Listener invokes + performClick + onClick MainActivity + onClick() implements
  • 20. View.performClick() /** * Call this view's OnClickListener, if it is defined. Performs all normal * actions associated with clicking: reporting accessibility event, playing * a sound, etc. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */ public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); return result; } https://github.com/android/platform_frameworks_base/blob/mast
  • 21. View.OnClickListener /** * Interface definition for a callback to be invoked when a view is clicked. */ public interface OnClickListener { /** * Called when a view has been clicked. * * @param v The view that was clicked. */ void onClick(View v); } https://github.com/android/platform_frameworks_base/blob/mast
  • 22. The Observer Pattern An extension of the Abstract Server pattern, enables to use many abstract servers. Instead of holding a listener in a single field, hold a collection. This way, you can add more than one listener. https://en.wikipedia.org/wiki/Observer_pattern
  • 23. Sample (Seen last week) The ViewTreeObserver is a great example. It’s an object that can notify you on things that happen on the Views tree, such as when animation completes, scroll changes, and etc.
  • 24. ViewTreeObserver - Ton of listener collections // Recursive listeners use CopyOnWriteArrayList private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners; private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners; private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners; private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners; private CopyOnWriteArrayList<OnEnterAnimationCompleteListener> mOnEnterAnimationCompleteListeners; // Non-recursive listeners use CopyOnWriteArray // Any listener invoked from ViewRootImpl.performTraversals() should not be recursive private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners; private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners; private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners; private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners; private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners; https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
  • 25. ViewTreeObserver - sample registration public void addOnWindowShownListener(OnWindowShownListener listener) { checkIsAlive(); if (mOnWindowShownListeners == null) { mOnWindowShownListeners = new CopyOnWriteArray<OnWindowShownListener>(); } mOnWindowShownListeners.add(listener); if (mWindowShown) { listener.onWindowShown(); } } https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
  • 26. ViewTreeObserver - sample invocation public final void dispatchOnWindowShown() { mWindowShown = true; final CopyOnWriteArray<OnWindowShownListener> listeners = mOnWindowShownListeners; if (listeners != null && listeners.size() > 0) { CopyOnWriteArray.Access<OnWindowShownListener> access = listeners.start(); try { int count = access.size(); for (int i = 0; i < count; i++) { access.get(i).onWindowShown(); } } finally { listeners.end(); } } } https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/ViewTreeObserver.java
  • 28. Static Factory Method - Flavor 1 Replace a constructor with a static (named) method, and hide the constructor as private. This way, the only (sane) way to create such class is via the static factory method.
  • 29. Toast.makeText(...) public class Toast { // ... public static Toast makeText(Context context, CharSequence text, @Duration int duration) { Toast result = new Toast(context); LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message); tv.setText(text); result.mNextView = v; result.mDuration = duration; return result; } https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
  • 30. Static Factory Method - Flavor 2 Create a static factory method for stuff your class might need. public class SomeActivity public Intent createSomeActivityIntent(int extraInt, String extraString){ // Create an intent, add the extras properly, and return the intent } }
  • 31. The Builder Pattern Sometimes, creation is more complicated, and you want to create a DSL for the creation, over creating many different constructors. This reduces mistakes (10x to code-autocompletion) and improves code readability and discoverability.
  • 33. AlertDialog.Builder public static class Builder { public Builder setTitle(@StringRes int titleId) public Builder setTitle(CharSequence title) public Builder setCustomTitle(View customTitleView) public Builder setMessage(@StringRes int messageId) public Builder setIcon(@DrawableRes int iconId) public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) public Builder setCancelable(boolean cancelable) public Builder setItems(@ArrayRes int itemsId, final OnClickListener listener) public Builder setAdapter(final ListAdapter adapter, final OnClickListener listener) public Builder setSingleChoiceItems(CharSequence[] items, int checkedItem, final OnClickListener listener) public Builder setView(int layoutResId) // ... public AlertDialog create() https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/AlertDialog.java#L438
  • 34. NotificationCompat.Builder public static class Builder public Builder setUsesChronometer(boolean b) public Builder setSmallIcon(int icon) public Builder setContentTitle(CharSequence title) public Builder setContentText(CharSequence text) public Builder setSubText(CharSequence text) public Builder setNumber(int number) public Builder setProgress(int max, int progress, boolean indeterminate) public Builder setContent(RemoteViews views) public Builder setDeleteIntent(PendingIntent intent) public Builder setTicker(CharSequence tickerText) public Builder setLargeIcon(Bitmap icon) public Builder setSound(Uri sound) public Builder setVibrate(long[] pattern) public Builder setOngoing(boolean ongoing) public Builder setAutoCancel(boolean autoCancel) public Builder setPriority(int pri) // ... https://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/app/NotificationCompat.java#L869
  • 35. Bonus Pattern: Fluent Interface (like it’s the 90s) Create a simple fluent interface, by having all methods return a builder, this builder. AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Hackathon Registration"); builder.setMessage("All team members must register TODAY."); builder.setPositiveButton("OK, I'm registered", null); builder.setNegativeButton("I'll register today", null); AlertDialog dialog = builder.create(); vs. AlertDialog dialog = new AlertDialog.Builder(this) .setTitle("Hackathon Registration") .setMessage("All team members must register TODAY.") .setPositiveButton("OK, I'm registered", null) .setNegativeButton("I'll register today", null) .create();
  • 38. Demo - Increase in Shekel Tish’im Meal Burger Meal Shnitzel Meal XL
  • 39. Demo - Increase in Shekel Tish’im public interface Meal { double getPrice(); String getChips(); String getMainCourse(); String getDrink(); } public class BurgerMeal implements Meal { public double getPrice() { return 10; } public String getChips() { return "Medium Chips"; } public String getMainCourse() { return "Burger"; } public String getDrink() { return "Medium Drink"; } }
  • 40. Demo - Increase in Shekel Tish’im public class XL implements Meal { private static final double XL_COST = 1.90; private Meal meal; public XL(Meal meal) { this.meal = meal; } public double getPrice() { double price = meal.getPrice() + XL_COST; return price; } public String getChips() { return "Extra large chips"; } } public String getMainCourse() { return meal.getMainCourse(); } public String getDrink() { return "Extra large drink"; }
  • 41. Exercise - Layered math problem We have an interface for getting sets of integers one at a time, and we have a class that implements it and provides 1, 2, ..., n, and code that reads such an IntProvider until it ends with n=3000. Using decorators, write the first 5 multiples of 7 that are larger than 38, and stop. IntProvider getCurrent : int moveNext : bool Credit: Iterator Pattern, Wikipedia
  • 42. Exercise - Layered math problem IntProvider getCurrent : int moveNext : bool This is our starting point: int n = 3000; IntProvider heartbeat = new IntHeartBeat(n); IntProvider result = heartbeat; while (result.moveNext()){ System.out.println(result.getCurrent()); }
  • 43. Solution - Layered math problem IntProvider skipped = new MultiplicationsOf(heartbeat, 7); IntProvider greaterThenThirtyEight = new PassGreaterThan(skipped, 38); IntProvider takeOnlyFive = new TakeOnly(greaterThenThirtyEight, 5); IntProvider result = takeOnlyFive;
  • 44. Solution - Layered math problem IntProvider skipped = new MultiplicationsOf(heartbeat, 7); IntProvider greaterThenThirtyEight = new PassGreaterThan(skipped, 38); IntProvider takeOnlyFive = new TakeOnly(greaterThenThirtyEight, 5); IntProvider result = takeOnlyFive; 7, 14, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ... 42, 49, 56, 63, 70, 77, 84, 91, 98, 105, ... 42, 49, 56, 63, 70 and STOP. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, ...
  • 45. Where is it found in the framework? Sample of Scroll View @Override public void addView(View child, ViewGroup.LayoutParams params) { if (getChildCount() > 0) { throw new IllegalStateException("ScrollView can host only one direct child"); } super.addView(child, params); } It extends FrameLayout but allows only one child. https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/ScrollView.java
  • 47. What did we see We saw a few Design Patterns Pattern Description SRC Abstract Server Adding abstraction to increase reusability Robert C. Martin Observer Subscribe to things that happen GoF Static Factory Method Invert ownership on creation instructions Add compile-time safety to Intent’s Extras Effective Java Builder Complex building scenario, avoid 2n constructors GoF Decorator Change object’s behavior without changing its interface, its code and its usages GoF