You are on page 1of 83

Android App Anatomy

Eric Burke
Square
@burke_eric

Thursday, November 22, 2012

Topics

Thursday, November 22, 2012

Topics
Android lifecycle
Fragments
Open source
Tape
Otto
Dagger

Thursday, November 22, 2012

Thursday, November 22, 2012

Thursday, November 22, 2012

ActionBarSherlock

Android Design on
every device.

Thursday, November 22, 2012

Lifecycle

Thursday, November 22, 2012

Install
Apps Run Forever
Uninstall

Thursday, November 22, 2012

Process 1

Process 2

Apps Run Forever

Thursday, November 22, 2012

Activity

Activity

Process 1

Activity
Process 2

Apps Run Forever

Thursday, November 22, 2012

R.I.P.
Static Variables
Activity

Activity

Process 1

Activity
Process 2

Apps Run Forever

Thursday, November 22, 2012

Thursday, November 22, 2012

10

Kill your process

Thursday, November 22, 2012

10

Thursday, November 22, 2012

11

Thursday, November 22, 2012

12

Tape

Thursday, November 22, 2012

13

If you respect
users, persist tasks
to disk.
- Jesse Wilson

Thursday, November 22, 2012

14

Dont Do This

Thursday, November 22, 2012

15

Server

Client UI

Loader or
Thread

Image File

Thursday, November 22, 2012

16

Do This

Pending

Thursday, November 22, 2012

17

Tape
Server
Client UI

add()

TaskQueue
UploadTask

Thursday, November 22, 2012

UploadTask

peek()
remove()

Service

18

Tape API
QueueFile
O(1) FIFO queue of byte[]
ObjectQueue
A queue of <T>
TaskQueue
Injects and starts tasks
Thursday, November 22, 2012

19

Fragment Lifecycle

Thursday, November 22, 2012

20

onCreate()

onSaveInstanceState()

Activity

Time
Thursday, November 22, 2012

21

Tap the Upload Button

Activity

Time
Thursday, November 22, 2012

22

Loader or Thread

Activity

Time
Thursday, November 22, 2012

23

DialogFragment

beginTransaction()
Loader or Thread

Activity

Time
Thursday, November 22, 2012

24

DialogFragment

commit()
Loader or Thread

Activity

onSaveInstanceState()
Time
Thursday, November 22, 2012

25

Square does not* use Loaders.

Thursday, November 22, 2012

26

Fragment Layout

Thursday, November 22, 2012

27

Thursday, November 22, 2012

28

Advantages
Smooth animations between steps
ActionBar does not move
Code organization

Thursday, November 22, 2012

29

Onboarding
Fragment

Fragment

Fragment

Settings
Fragment
Fragment

Thursday, November 22, 2012

Fragment

Payment Flow
Fragment

Fragment

Fragment

30

Fragment Activity
Communication
Containing
Activity

Fragment

implements

defines

Listener
Interface

http://developer.android.com/training/basics/fragments/communicating.html
Thursday, November 22, 2012

31

Listener Interface
public class NewsFragment extends Fragment {
private Listener listener;
public interface Listener {
void onItemSelected(int position);
}
@Override public void onAttach(Activity a) {
super.onAttach(a);
listener = (Listener) a;
}
}
Thursday, November 22, 2012

32

Activity
public class HomeActivity extends Activity
implements NewsFragment.Listener {
@Override
public void onItemSelected(int position) {

}
}

Thursday, November 22, 2012

33

public class Onboarding extends Activity


implements AccountFragment.Listener,
ActivateFragment.Listener,
ShippingFragment.Listener,
BankFragment.Listener,
etc...
{
// The god object...
}

Thursday, November 22, 2012

34

Fragment
Fragment

Fragment

Activity
Fragment

Fragment
Fragment

How can Fragments communicate without


tight Activity coupling?
Thursday, November 22, 2012

35

Publish

Subscribe

Fragment

Fragment

Fragment
Service

Thursday, November 22, 2012

Bus

Fragment
Activity

36

LocalBroadcastManager
Included in Android Support library
Publishes Intents within your
process

Thursday, November 22, 2012

37

Publishing
Intent intent = new Intent(
BroadcastIds.LOCATION_UPDATED_ACTION);
intent.putExtra(
BroadcastIds.CURRENT_LOCATION_KEY,
getCurrentLocation());
LocalBroadcastManager.getInstance(
getActivity()).sendBroadcast(intent);

Thursday, November 22, 2012

38

Publishing
Intent intent = new Intent(
BroadcastIds.LOCATION_UPDATED_ACTION);
intent.putExtra(
BroadcastIds.CURRENT_LOCATION_KEY,
getCurrentLocation());
LocalBroadcastManager.getInstance(
getActivity()).sendBroadcast(intent);

Thursday, November 22, 2012

39

Publishing
Intent intent = new Intent(
BroadcastIds.LOCATION_UPDATED_ACTION);
intent.putExtra(
BroadcastIds.CURRENT_LOCATION_KEY,
getCurrentLocation());
LocalBroadcastManager.getInstance(
getActivity()).sendBroadcast(intent);

Thursday, November 22, 2012

40

Subscribing
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override public void onReceive(
Context context, Intent intent) {
Location location =
(Location) intent.getParcelableExtra(
BroadcastIds.CURRENT_LOCATION_KEY);
showLocation(location);
}
};

Thursday, November 22, 2012

41

Subscribing
IntentFilter locationFilter = new IntentFilter(
BroadcastIds.LOCATION_UPDATED_ACTION);
@Override public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(getActivity())
.registerReceiver(receiver, locationFilter);
}
@Override public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getActivity())
.unregisterReceiver(receiver);
}
Thursday, November 22, 2012

42

Boilerplate.
No type safety.
Hard to test.

Thursday, November 22, 2012

43

Otto

Thursday, November 22, 2012

44

Registration
public class BaseFragment extends Fragment {
@Inject Bus bus;
@Override public void onResume() {
super.onResume();
bus.register(this);
}
@Override public void onPause() {
super.onPause();
bus.unregister(this);
}
}
Thursday, November 22, 2012

45

Registration
public class BaseFragment extends Fragment {
@Inject Bus bus;
@Override public void onResume() {
super.onResume();
bus.register(this);
}

@Override public void onPause() {


super.onPause();
bus.unregister(this);
}
Fails fast at

Thursday, November 22, 2012

runtime.
46

Subscribing
@Subscribe
public void onLocationUpdated(Location l) {
showLocation(l);
}

Receives any type


extending Location.
Thursday, November 22, 2012

47

Publishing
bus.post(getCurrentLocation());

Synchronous
delivery.
Thursday, November 22, 2012

48

@Produce
(getting data the first time)

Thursday, November 22, 2012

49

How to get
this image?

Thursday, November 22, 2012

50

Downloader

post(UserImage)

Bus

UserImageCache

Thursday, November 22, 2012

51

Subscribing
public class AccountActivity
extends BaseActivity {
@Subscribe public void onUserImageUpdated(
UserImage image) {
((ImageView) findViewById(R.id.image))
.setImageBitmap(image.getBitmap());
}

Thursday, November 22, 2012

52

get()

done()

onResume()

Downloader

onPause()

Activity

UserImageCache

Thursday, November 22, 2012

53

Producers
@Singleton public class UserImageCache {
@Produce
public UserImage produceUserImage() {
return cachedUserImage;
}

Thursday, November 22, 2012

54

Activity

@Subscribe
Bus

@Produce
UserImageCache

Thursday, November 22, 2012

55

@Produce decouples
threads from the Activity
and Fragment lifecycle.

Thursday, November 22, 2012

56

Otto API Summary


register(), unregister(), post()
@Subscribe, @Produce
Thread confinement
Easy to test!
Thursday, November 22, 2012

57

Origins of Otto
Forked from Guavas EventBus
Optimized for Android - 16k!
Less reflection; more caching

Thursday, November 22, 2012

58

Dependency
Injection

Thursday, November 22, 2012

59

Guice on Android?
Weve used it for 2+ years
Startup performance is a challenge
Runtime error checking
See also: RoboGuice
Thursday, November 22, 2012

60

Can we do better?

Thursday, November 22, 2012

61

Dagger

Thursday, November 22, 2012

62

Thursday, November 22, 2012

What is Dagger?

63

What is Dagger?

Compile-time
dependency injection.

Thursday, November 22, 2012

63

@Inject

import javax.inject.Inject; // JSR-330


public class PublishFragment
extends BaseFragment {
@Inject Bus bus;
@Inject LocationManager locationManager;

Thursday, November 22, 2012

64

Constructor Injection

public class AccountUpdater {


private final Bus bus;
private final AccountService accounts;
@Inject public AccountUpdater(Bus bus,
AccountService accounts) {
this.bus = bus;
this.accounts = accounts;
}
}
Thursday, November 22, 2012

65

Module

@Module(
entryPoints = {
HomeActivity.class,
PublishFragment.class,
SubscribeFragment.class
}
)
public class ExampleModule {
@Provides @Singleton Bus provideBus() {
return new Bus();
}
}
Thursday, November 22, 2012

66

Module

@Module(
entryPoints = {
HomeActivity.class,
PublishFragment.class,
SubscribeFragment.class
}
)
public class ExampleModule {
@Provides @Singleton Bus provideBus() {
return new Bus();
}
}
Thursday, November 22, 2012

67

Missing Provider
Method?
No injectable members on com.squareup.otto.Bus.
Do you want to add an injectable constructor?
required by com.squareup.anatomy.PublishFragment
for com.squareup.anatomy.ExampleModule

Thursday, November 22, 2012

68

Bootstrapping

public class ExampleApp extends Application {


private ObjectGraph objectGraph;
@Override public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.get(
new ExampleModule(this));
}
public ObjectGraph objectGraph() {
return objectGraph;
}
}
Thursday, November 22, 2012

69

Bootstrapping

public class ExampleApp extends Application {


private ObjectGraph objectGraph;
@Override public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.get(
new ExampleModule(this));
}
public ObjectGraph objectGraph() {
return objectGraph;
}
}
Thursday, November 22, 2012

70

Bootstrapping

public class ExampleApp extends Application {


private ObjectGraph objectGraph;
@Override public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.get(
new ExampleModule(this));
}
public ObjectGraph objectGraph() {
return objectGraph;
}
}
Thursday, November 22, 2012

71

Bootstrapping

public class ExampleApp extends Application {


private ObjectGraph objectGraph;
@Override public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.get(
new ExampleModule(this));
}
public ObjectGraph objectGraph() {
return objectGraph;
}
}
Thursday, November 22, 2012

72


Fragment

ExampleApp
(ObjectGraph)

BaseFragment

NameFragment

Thursday, November 22, 2012

AddressFragment

73

Fragment Injection

public class BaseFragment extends Fragment {


@Override
public void onCreate(Bundle state) {
super.onCreate(state);
((ExampleApp) getActivity()
.getApplication())
.objectGraph().inject(this);
}
}

Thursday, November 22, 2012

74

Fragment Injection

public class BaseFragment extends Fragment {


@Override
public void onCreate(Bundle state) {
super.onCreate(state);
((ExampleApp) getActivity()
.getApplication())
.objectGraph().inject(this);
}
}

Thursday, November 22, 2012

75

Fragment Injection

public class BaseFragment extends Fragment {


@Override
public void onCreate(Bundle state) {
super.onCreate(state);
((ExampleApp) getActivity()
.getApplication())
.objectGraph().inject(this);
}
}

Thursday, November 22, 2012

76

Dagger Limitations
No final and private field injection
No method injection
No scopes
@Assisted

Thursday, November 22, 2012

77

Dagger Features
Compile time injection
Very little magic
ber fast

Thursday, November 22, 2012

78

The End.
Tape square.github.com/tape/
Otto square.github.com/otto/
ActionBarSherlock actionbarsherlock.com

Thursday, November 22, 2012

Dagger github.com/square/dagger

79

You might also like