android app anatomy
play

Android App Anatomy Eric Burke Square @burke_eric Topics Android - PowerPoint PPT Presentation

Android App Anatomy Eric Burke Square @burke_eric Topics Android lifecycle Fragments Open source Tape Otto Dagger ActionBarSherlock Android Design on every device. Lifecycle Install Apps Run Forever Uninstall


  1. Android App Anatomy Eric Burke Square @burke_eric

  2. Topics • Android lifecycle • Fragments • Open source • Tape • Otto • Dagger

  3. ActionBarSherlock Android Design on every device.

  4. Lifecycle

  5. Install Apps Run Forever Uninstall

  6. Process 1 Process 2 Apps Run Forever

  7. Activity Activity Activity Process 1 Process 2 Apps Run Forever

  8. R.I.P . Static Variables Activity Activity Activity Process 1 Process 2 Apps Run Forever

  9. Kill your process

  10. Tape

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

  12. Don’t Do This

  13. Server Loader or Client UI Thread Image File

  14. Do This Pending

  15. Tape API • QueueFile • O(1) FIFO queue of byte[] • ObjectQueue • A queue of <T> • TaskQueue • Injects and starts tasks

  16. Tape Server Client UI TaskQueue peek() remove() add() Service UploadTask UploadTask

  17. Usage Pattern 1. UI adds to a TaskQueue: queue.add(new ImageUploadTask(image)); 2. Start the Android Service: context.startService(new Intent(context, ImageUploadTaskService.class));

  18. 3. Service executes the next task: Task t = queue.peek(); t.execute(this); // Listener 4. If successful: queue.remove(); executeNext(); 5. If failure, schedule a retry.

  19. Retrying Failed Tasks • Always process tasks in order: FIFO • Distinguish between client bugs vs. network or server exceptions • Client errors - do not retry • Server & network errors - retry

  20. Fragment Lifecycle

  21. onCreate() onSaveInstanceState() Activity Time ➞

  22. Tap the Upload Button Activity Time ➞

  23. Loader or Thread Activity Time ➞

  24. DialogFragment beginTransaction() Loader or Thread Activity Time ➞

  25. DialogFragment commit() Loader or Thread Activity onSaveInstanceState() Time ➞

  26. Square does not* use Loaders.

  27. Fragment Layout

  28. Advantages • Smooth animations between steps • ActionBar does not move • Code organization

  29. Onboarding Fragment Fragment Fragment Payment Flow Settings Fragment Fragment Fragment Fragment Fragment Fragment

  30. Fragment → Activity Communication implements Containing Activity defines Listener Fragment Interface http://developer.android.com/training/basics/fragments/communicating.html

  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; } }

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

  33. public class Onboarding extends Activity implements AccountFragment.Listener, ActivateFragment.Listener, ShippingFragment.Listener, BankFragment.Listener, etc... { // The god object... }

  34. Fragment Fragment Fragment Activity Fragment Fragment Fragment How can Fragments communicate without tight Activity coupling?

  35. Publish Subscribe Fragment Fragment Bus Fragment Fragment Service Activity

  36. LocalBroadcastManager • Included in Android Support library • Publishes Intents within your process

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

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

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

  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); } };

  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); }

  42. Boilerplate. No type safety. Hard to test.

  43. Otto

  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); } }

  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 } } runtime.

  46. Subscribing @Subscribe public void onLocationUpdated(Location l) { showLocation(l); } Receives any type extending Location.

  47. Publishing bus.post (getCurrentLocation()); Synchronous delivery.

  48. @Produce (getting data the first time)

  49. How to get this image?

  50. post(UserImage) Downloader Bus UserImageCache

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

  52. get() done() onResume() onPause() Downloader Activity UserImageCache

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

  54. Activity @Subscribe Bus @Produce UserImageCache

  55. @Produce decouples threads from the Activity and Fragment lifecycle.

  56. Otto API Summary • register(), unregister(), post() • @Subscribe, @Produce • Thread confinement • Easy to test!

  57. Origins of Otto • Forked from Guava’s EventBus • Optimized for Android - 16k! • Less reflection; more caching

  58. Dependency Injection

  59. Guice on Android? • We’ve used it for 2+ years • Startup performance is a challenge • Runtime error checking • See also: RoboGuice

  60. Can we do better?

  61. Dagger †

  62. † What is Dagger? Compile-time dependency injection.

  63. † @Inject import javax.inject.Inject; // JSR-330 public class PublishFragment extends BaseFragment { @Inject Bus bus; @Inject LocationManager locationManager; … }

  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; } }

  65. † Module @Module( entryPoints = { HomeActivity.class, PublishFragment.class, SubscribeFragment.class } ) public class ExampleModule { @Provides @Singleton Bus provideBus() { return new Bus(); } }

  66. † Module @Module( entryPoints = { HomeActivity.class, PublishFragment.class, SubscribeFragment.class } ) public class ExampleModule { @Provides @Singleton Bus provideBus() { return new Bus(); } }

  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

  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; } }

  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; } }

  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; } }

  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; } }

  72. † Fragment ExampleApp (ObjectGraph) BaseFragment NameFragment AddressFragment

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