1 of 39

tinkering with

android architectures

@nhpatt / Javier Gamarra

2 of 39

3 of 39

@nhpatt (gmail | twitter)

http://bit.ly/tinkeringandroid

@liferay

4 of 39

please,

ask questions

5 of 39

Context

6 of 39

La La App

7 of 39

rotation change (state)

recreates the class

8 of 39

DRAMA

9 of 39

Several dramas

  • Lost state
  • View position lost

10 of 39

Async Task

private class ...AsyncTask

extends AsyncTask<Object, Void, Object> {

protected Object doInBackground(Object... params) {

try {

return networkRequest().result

} catch (IOException e) {}

}

protected void onPostExecute(Object result) {

adapter.notifyDataSetChanged();

}

}

11 of 39

Memory Leak

private static class ...AsyncTask

extends AsyncTask<Object, Void, Object> {

protected Object doInBackground(Object... params) {

try {

return networkRequest().result

} catch (IOException e) {}

}

protected void onPostExecute(Object result) {

adapter.notifyDataSetChanged(); // doesn’t compile

}

}

12 of 39

everything in the same class

public class ...AsyncTask

extends AsyncTask<Object, Void, Object> {

protected Object doInBackground(Object... params) {

try {

return networkRequest().result

} catch (IOException e) {}

}

protected void onPostExecute(Object result) {

activity.notifyUI(locations);

}

public ListFilmLocationsAsyncTask(MainActivity mainActivity) {

this.activity = mainActivity;

}

13 of 39

exception

public class ...AsyncTask

extends AsyncTask<Object, Void, Object> {

protected Object doInBackground(Object... params) {

try {

return networkRequest().result

} catch (IOException e) {}

}

protected void onPostExecute(Object result) {

if (activity != null && !activity.isDestroyed() ...) {

activity.notifyUI(locations);

}

}

14 of 39

Several dramas

  • Lost state
  • View position lost
  • Memory leak
  • No separation of concerns: everything in the same class
  • Exception if we are not careful
  • Result lost in rotation and several network operations

15 of 39

Several dramas… in Android

16 of 39

Solution in detail

  • Interactors
  • Callbacks
  • Events

17 of 39

Set a callback and don’t return anything?

public void requestPassword(... args) throws Exception {

validate(...);

Session session = new SessionImpl(...);

session.setCallback(new Callback(getTargetScreenletId()));

Service service = getService(session);

service.sendPasswordByEmailAddress(companyId, emailAddress);

}

18 of 39

???

public void onEvent(ForgotPasswordEvent event) {

if (!isValidEvent(event)) {return;}

if (event.isFailed()) {

getListener().error(event.getException());

} else {

getListener().success(event.isPasswordSent());

}

}

19 of 39

Event Bus! (2012-2013 solution)

20 of 39

Solution

  • Event Bus

21 of 39

Solution in detail

  • Explicit Event Bus
    • with targetScreenletId && isValidEvent

  • Big class hierarchy, heavily typed

22 of 39

Dramas vs solutions

  • Lost state -> eventbus/onsave
  • View position lost -> onsave/onrestore
  • Memory leak -> eventbus
  • No separation of concerns -> interactors
  • Exception if we are not careful -> eventbus
  • Result lost and several network operations -> programmer

23 of 39

And the cache?

24 of 39

Cache...

  • SQL based
  • Explicitly modelled
  • Explicitly called

Impossible to create a transparent solution

25 of 39

A mess

26 of 39

A mess

  • Hard to implement an interactor
  • Async is hard
  • Lots of strange concepts
  • Really hard to implement a cached interactor
  • Cross cutting concerns are difficult

27 of 39

Other solutions

  • Block orientation/flags
  • Statics/Application Class
  • Special Android method -> Retain
  • Rx
  • Cache
  • ...

28 of 39

v2

public BasicEvent execute(Object[] args) throws Exception {

validate(url, folderId);

JSONObject jsonObject = doNetworkCall(url, title, folderId);

return new BasicEvent(jsonObject);

}

public void onSuccess(BasicEvent event) {

getListener().success();

}

public void onFailure(BasicEvent event) {

getListener().error(event.getException());

}

29 of 39

So… v2

  • Interactors run in background
  • Events are decorated
  • EventBus still used but hidden
  • Consistent error treatment

30 of 39

Cache...

  • Key/Value
  • Based on decorating events with a key
  • Really easy to implement

31 of 39

This is nicer...

32 of 39

But...

  • Varargs
  • Still “callbacks”
  • Cache is nice but clunky

33 of 39

How it should be done?

34 of 39

v3?

public void execute(Event event) throws Exception {

try {

validate(event);

JSONObject jsonObject = doNetworkCall(event);

getListener().success(new BasicEvent(jsonObject));

} catch (Exception e) {

getListener().error(e);

}

}

35 of 39

v3?

// Cache should be here

public void execute(Event event) throws Exception {

try {

validate(event);

// Or inside here

JSONObject jsonObject = doNetworkCall(event);

getListener().success(new BasicEvent(jsonObject));

} catch (Exception e) {

getListener().error(e);

}

}

36 of 39

So… v3?

  • Rx?
  • Cache at Network Level?
  • Intercept API?
  • ...

37 of 39

questions?

Questions?

38 of 39

tinkering with

android architectures

@nhpatt / Javier Gamarra

39 of 39

Future?