a simple scalable app architecture with android
play

A simple, scalable app architecture with Android annotations Luke - PowerPoint PPT Presentation

A simple, scalable app architecture with Android annotations Luke Sleeman Freelance Android developer lukesleeman.com.au Image CC: https://flic.kr/p/6oqCZB Agenda Introduction The architecture - an overview Services Domain


  1. A simple, scalable app architecture with Android annotations Luke Sleeman Freelance Android developer lukesleeman.com.au Image CC: https://flic.kr/p/6oqCZB

  2. Agenda • Introduction • The architecture - an overview • Services • Domain object • Testing • UI • Other issues • Closing thoughts

  3. Introduction - why we need this at all

  4. Goals • Quick, simple • Typically data driven apps - get some stuff from a web service, store it locally, show it to the user, submit stuff back to the web service • Scalable - Handle small apps and big ones • Unsurprising, easy to jump in and out of, clear and concise, makes sense to anybody. ‘Obvious’. • Testable • Need to be able to incrementally evolve towards it from an existing codebase • Boring!

  5. The architecture! User Interface Domain objects Services

  6. This is what it looks like

  7. So what about Android annotations? AndroidAnnotations User Interface Domain objects Services

  8. What is AndroidAnnotations? • Annotate your code - works of JDK annotations • Code generation - you can look behind the curtain to see how the magic works. MyActivity_ • Includes annotation support for a lot of other libraries I use such as ormlite • You don’t have to use it • But you would be silly not to :-)

  9. Services User Interface Domain objects Services

  10. Typical methods List<Users> getUsersFromWebservice() � AndroidDatabaseResults searchForSite(String searchText) � UserInfo getInfoFromFacebook(int key)

  11. A Simple Service public class PizzaService { private static List<Pizza> pizzas; public static List<Pizza> getPizzas(){ if(pizzas == null){ pizzas = new ArrayList<Pizza>(); pizzas.add(new Pizza("Luke Special", 10.50)); pizzas.add(new Pizza("Margherita", 9.50)); } return pizzas; } }

  12. A more complex service @EBean(scope = EBean.Scope.Singleton) 
 public class FriendService { @OrmLiteDao(helper = ExampleDBHelper.class, model = Friend.class) 
 protected RuntimeExceptionDao<Friend, String> friendsDao; @RestService 
 protected FriendListWebservice webservice; public List<Friend> getFriends(){ 
 return friendsDao.queryForAll(); 
 } public void downloadAndSaveFriend(int id)throws IOException { 
 Friend newFriend = webservice.getFriend(id); 
 friendsDao.create(newFriend); 
 } 
 }

  13. Domain objects User Interface Domain objects Services

  14. A simple domain object public class Pizza { � private String name; private double price; � public Pizza(String name, double price) { this.name = name; this.price = price; } � public String getName() { return name; } � public void setName(String name) {

  15. A more complex domain object @DatabaseTable 
 public class Friend { � @DatabaseField(generatedId = true) 
 private int id; � @DatabaseField 
 private String userName; � public int getId() { 
 return id; 
 } � public void setId(int id) { 
 this.id = id; 
 } � public String getUserName() { 
 return userName; 


  16. Domain objects Relationships

  17. Domain objects Relationships • Option 1 - In the objects @ForeignCollectionField(foreignFieldName = "user") 
 private List<EmailAddress> addresses; • Option 2 - In the service public List<EmailAddress> getFriendEmails(int id)

  18. Unit tests User Interface Domain objects Unit Tests Services

  19. A basic test public class PizzaTest extends AndroidTestCase{ public void testGetPizzas(){ List<Pizza> pizzaList = PizzaService.getPizzas(); assertNotNull(pizzaList); } } � public class FriendTest extends AndroidTestCase { public void testFriend(){ FriendService friendService = FriendService_.getInstance_(getContext()); assertNotNull(friendService.getFriends()); } }

  20. A more advanced test public class FriendTest extends AndroidTestCase { @Override 
 protected void setUp() throws Exception { 
 File database = getContext().getDatabasePath(ExampleDBHelper.DB_NAME); 
 if (database.exists()) { 
 database.delete(); 
 } 
 } public void testSearchFriends(){ 
 FriendService service = FriendService_.getInstance_(getContext()); 
 service.createOrUpdateFriend(new Friend("Luke")); 
 assertEquals(1, friendService.search("lu").size()); 
 } }

  21. A nifty trick public void downloadAndPatchFriendList() 
 throws IOException{ String patchFile = downloadPatchFile(); 
 List<Friend> updatedFriends = parsePatch(patchFile); 
 mergeFriendsWithDB(updatedFriends); }

  22. A nifty trick @EBean(scope = EBean.Scope.Singleton) 
 public class TestFriendService extends FriendService { @Override 
 public void mergeFriendWithDB(List<Friend> updatedFriends){ 
 super.mergeFriendsWithDB(updatedFriends); 
 } @Override 
 public List<Friend> parsePatch(String patchFile) { 
 return super.parsePatch(patchFile); 
 } }

  23. A nifty trick private TestFriendService testFriendService = 
 TestFriendService_.getInstance_(getContext()); � public void testParseEmpty(){ List<Friend> friends = testFriendService.parsePatch(EMPTY_PATCH); assert... } � public void testParseModifyFriends(){ List<Friend> friends = testFriendService.parsePatch(MODIFY_PATCH); assert... }

  24. The UI User Interface Domain objects Services

  25. This is where android annotations really shines • @EActivity, @EFragment, @EViewGroup • @ViewByID @FragmentByID, etc • @DrawableRes @AnimationRes, @HtmlRes • @Click, @ListClick

  26. Getting services and domain objects @EActivity(R.layout.activity_best_friend) 
 public class BestFriendActivity extends Activity { @ViewById(R.id.best_friend_text) 
 protected TextView bestFriendText; @Bean 
 protected FriendService friendService; private Friend bestFriend; @AfterViews 
 protected void setupBestFriend(){ 
 bestFriend = friendService.getBestFriend(); 
 bestFriendText.setText(bestFriend.getName()); 
 } @Click(R.id.poke_friend_button) 
 protected void poke(){ 
 friendService.poke(bestFriend); 
 } }

  27. Threading @EActivity(R.layout.activity_friend_list) 
 public class FriendListActivity extends Activity { @ViewById(R.id.friend_list) 
 protected ListView list; @ViewById(R.id.loading_progress) 
 protected ProgressBar progressSpinner; @Bean 
 protected FriendService service; @AfterViews 
 protected void startDownload(){ 
 progressSpinner.setVisibility(View.VISIBLE); 
 downloadFriends(); 
 }

  28. Threading @Background 
 protected void downloadFriends(){ 
 try{ List<Friends> friendList = service.downloadFriendList(); 
 displayFriends(friendList); 
 } 
 catch(IOException e){ 
 displayDownloadError(); 
 } 
 } @UiThread 
 protected void displayFriends(List<Friends> friendList){ 
 progressSpinner.setVisibility(View.GONE); 
 … 
 } � @UiThread 
 protected void displayDownloadError(){ 
 progressSpinner.setVisibility(View.GONE); 
 … 
 } }

  29. There is a bug!

  30. Threading @Background 
 protected void downloadFriends(){ 
 try{ List<Friends> friendList = service.downloadFriendList(); 
 displayFriends(friendList); 
 } 
 catch(IOException e){ 
 displayDownloadError(); 
 } 
 } @UiThread 
 protected void displayFriends(List<Friends> friendList){ 
 progressSpinner.setVisibility(View.GONE); 
 … 
 } � @UiThread 
 protected void displayDownloadError(){ 
 progressSpinner.setVisibility(View.GONE); 
 … 
 } }

  31. 
 
 Threading - dealing with activity shutdown • Option 1 - Let our background task run and don’t update ui @UiThread 
 protected void displayFriends(List<Friend> friendList){ 
 if(isDestroyed()) return; 
 … Option 2 - Cancel background task 
 @Background(id = "download") 
 protected void downloadFriends(){ …. } 
 @Override 
 protected void onDestroy() { 
 BackgroundExecutor.cancelAll("download", false); 
 super.onDestroy(); 
 }

  32. Other issues

  33. Evolving an existing apps architecture 1. Add in android annotations and clean out boilerplate 2. If you don’t have them start creating domain objects - move logic from UI into them. 3. If you don’t have them start creating services - have them mange your domain objects

  34. Things to look at changing • Different libraries replace AA (dagger, retrofit, butterknife) • EventBus or RXJava • Pinch ideas from the google io app. • Come up with a good way to manage fragments

  35. Closing thoughts

  36. A humble request • Architecture is important! • Don’t be satisfied with just the simple architecture presented … • Think about architecture! • Talk about architecture! • Develop new architectures!

  37. Questions?

  38. Bonus slides

  39. When not to use this architecture • Games • If your building one app over the course of years • If you can develop a large internal library of reusable components

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend