Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Put your Activity on a Diet

Put your Activity on a Diet

This talk to share the journey we took at SoundCloud to break our activities and fragments into small components easier to unit test.

Guillaume Lung

June 03, 2015
Tweet

More Decks by Guillaume Lung

Other Decks in Programming

Transcript

  1. [...] @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.container_layout); connectivityListener.registerHandler(connHandler,

    CONNECTIVITY_MSG); mUnauthoriedRequestReceiver = new UnauthorisedRequestReceiver (getApplicationContext(), getSupportFragmentManager()); setVolumeControlStream(AudioManager.STREAM_MUSIC); registerReceiver(mLoggingOutListener, new IntentFilter(Actions. LOGGING_OUT)); mOnCreateCalled = true; mIsFirstRun = savedInstanceState == null; } [...] Fat activities title, date, 01 of 10
  2. [...] @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.container_layout); networkConnectivityController.onCreate();

    unauthorisedRequestController.onCreate(getApplicationContext(), ...); screenStateProvider.onCreate(savedInstanceState); setVolumeControlStream(AudioManager.STREAM_MUSIC); } [...] Separation of concerns title, date, 01 of 10
  3. Problems title, date, 01 of 10 • Boiler plate •

    No contract • Error prone [...] public void onPause() { screenStateProvider.onResume(activity); } [...]
  4. Solutions title, date, 01 of 10 public class ActivityLightCycleDispatcher {

    ... } public void add(ActivityLightCycle lightCycle) { ... } public void onCreate(Activity activity, Bundle bundle) { ... } public void onResume(Activity activity) { ... } [...] } public interface ActivityLightCycle { void onCreate(Activity activity, Bundle bundle); void onResume(Activity activity); [...] }
  5. public class LightCycleActivity extends Activity implements LightCycleDispatcher { public void

    attach(ActivityLightCycle lightCycle) { dispatcher.add(lightCycle); } protected void onCreate(Bundle savedInstanceState) { dispatcher.onCreate(this, savedInstanceState); } [...] } Separation of concerns title, date, 01 of 10
  6. public class MyActivity extends LightCycleActivity { [...] public MyActivity() {

    attach(networkConnectivityLightCycle); attach(unauthorisedRequestLightCycle); attach(screenStateLightCycle); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.container_layout); setVolumeControlStream(AudioManager.STREAM_MUSIC); } [...] } Separation of concerns title, date, 01 of 10
  7. Apply LightCycle to the code base title, date, 01 of

    10 • All components implement the same interface • Add tests when extracting • Hook up light cycles in the base activity
  8. There is still some boiler plate. title, date, 01 of

    10 public class MyActivity extends LightCycleActivity { [...] public MyActivity() { attach(networkConnectivityLightCycle); attach(unauthorisedRequestLightCycle); attach(screenStateLightCycle); }
  9. There is still some boiler plate title, date, 01 of

    10 public class MyActivity extends LightCycleActivity { @LightCycle NetworkConnectivityLightCycle networkConnectivityLightCycle; @LightCycle UnauthorisedRequestLightCycle unauthorisedRequestLightCycle; @LightCycle ScreenStateLightCycle screenStateLightCycle; public MyActivity() { LightCycleBinder.bind(this); } [...] }
  10. Responsabilities title, date, 01 of 10 • Activities ◦ thin

    component ◦ hook up light cycle components • LightCycles ◦ Do one thing ◦ Agnostic to the Activity they are attached to. ◦ Independent from the others ◦ Platform independant as much as possible ◦ Tested
  11. More title, date, 01 of 10 • Works for fragments

    too • You can build it if you need it (< 1000 lines). • Maybe open sourced (TBD)