A simple, scalable app architecture with Android annotations
Luke Sleeman Freelance Android developer lukesleeman.com.au Image CC: https://flic.kr/p/6oqCZB
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
Luke Sleeman Freelance Android developer lukesleeman.com.au Image CC: https://flic.kr/p/6oqCZB
locally, show it to the user, submit stuff back to the web service
sense to anybody. ‘Obvious’.
codebase
curtain to see how the magic works. MyActivity_
libraries I use such as ormlite
List<Users> getUsersFromWebservice()
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; } }
@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); } }
public class Pizza {
private double price;
this.name = name; this.price = price; }
return name; }
@DatabaseTable public class Friend {
private int id;
private String userName;
return id; }
this.id = id; }
return userName;
@ForeignCollectionField(foreignFieldName = "user") private List<EmailAddress> addresses;
public List<EmailAddress> getFriendEmails(int id)
public class PizzaTest extends AndroidTestCase{ public void testGetPizzas(){ List<Pizza> pizzaList = PizzaService.getPizzas(); assertNotNull(pizzaList); } }
public void testFriend(){ FriendService friendService = FriendService_.getInstance_(getContext()); assertNotNull(friendService.getFriends()); } }
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()); } }
public void downloadAndPatchFriendList() throws IOException{ String patchFile = downloadPatchFile(); List<Friend> updatedFriends = parsePatch(patchFile); mergeFriendsWithDB(updatedFriends); }
@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); } }
private TestFriendService testFriendService = TestFriendService_.getInstance_(getContext());
List<Friend> friends = testFriendService.parsePatch(EMPTY_PATCH); assert... }
List<Friend> friends = testFriendService.parsePatch(MODIFY_PATCH); assert... }
@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); } }
@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(); }
@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); … }
protected void displayDownloadError(){ progressSpinner.setVisibility(View.GONE); … } }
@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); … }
protected void displayDownloadError(){ progressSpinner.setVisibility(View.GONE); … } }
@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(); }
boilerplate
have them mange your domain objects
butterknife)
presented …
reusable components