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

Código limpio en la UI para Android, mejores prácticas.

Código limpio en la UI para Android, mejores prácticas.

Consejos basicos para un codigo mas limpio en tu UI.

Cristian Fabian Gómez Rojas

February 21, 2017
Tweet

More Decks by Cristian Fabian Gómez Rojas

Other Decks in Programming

Transcript

  1. “ El codigo limpio puede ser legible por una persona

    diferente al autor… tiene pruebas… usa nombres adecuados… cuenta con dependencias minimas… tiene un API reducido…
  2. Codigo Limpio ▪ Ligibilidad ▪ Pruebas ▪ Nombramiento ▪ Dependencias

    ▪ API reducido Estás seguro que tu codigo es limpio?
  3. Codigo Android ▪ Separa las reglas de negocio de la

    presentación. ▪ Buenas prácticas? ▪ Como manejar todo el código restante? ▪ Deja de hablar en Android, habla con propósito.
  4. class MyActivity extends AppCompatActivity { @OnClick(R.id.button) public void onButtonAction(){ RequestTask

    task = new RequestTask(); task.exec(); } @OnClick(R.id.button1) public void onButton1Action(){ Reques1tTask task = new Request1Task(); task.exec(); } static class RequestTask() extends AsyncTask {...} static class Request1Task() extends AsyncTask {...} }
  5. class LoginActivity extends AppCompatActivity { @OnClick(R.id.login_button) public void onLoginButtonClicked() {

    String username = usernameField.content(); String password = passwordField.content(); loginAction.auth(username, password).subscribe({ showHomeScreen() }, { showErrorMessage() }); } @OnClick(R.id.login_facebook_button) public void onLoginFacebbokButtonClicked() { facebookAction.auth().subscribe({ showHomeScreen() }, { showErrorMessage() }); } }
  6. Testing UI ▪ Given/When/Then ▪ Espresso - Flebox layout by

    Google ▪ Chequeo de Intents ▪ Chequeo de información ▪ Navegacion correcta ▪ Screenshots ▪ Inversión de dependencias - Fabio Collini / Adrian Catalan
  7. @RunWith(AndroidJUnit4.class) @MediumTest public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> mActivityRule

    = new ActivityTestRule<>(MainActivity.class); @Test @FlakyTest public void testAddFlexItem() { MainActivity activity = mActivityRule.getActivity(); FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout); assertNotNull(flexboxLayout); int beforeCount = flexboxLayout.getChildCount(); onView(withId(R.id.add_fab)).perform(click()); assertThat(flexboxLayout.getChildCount(), is(beforeCount + 1)); } }
  8. @RunWith(AndroidJUnit4.class) @MediumTest public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> mActivityRule

    = new ActivityTestRule<>(MainActivity.class); @Test @FlakyTest public void testAddFlexItem() { MainActivity activity = mActivityRule.getActivity(); FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout); assertNotNull(flexboxLayout); int beforeCount = flexboxLayout.getChildCount(); onView(withId(R.id.add_fab)).perform(click()); assertThat(flexboxLayout.getChildCount(), is(beforeCount + 1)); } }
  9. @RunWith(AndroidJUnit4.class) @MediumTest public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> mActivityRule

    = new ActivityTestRule<>(MainActivity.class); @Test @FlakyTest public void testAddFlexItem() { MainActivity activity = mActivityRule.getActivity(); FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout); assertNotNull(flexboxLayout); int beforeCount = flexboxLayout.getChildCount(); onView(withId(R.id.add_fab)).perform(click()); assertThat(flexboxLayout.getChildCount(), is(beforeCount + 1)); } }
  10. @RunWith(AndroidJUnit4.class) @MediumTest public class MainActivityTest { @Rule public ActivityTestRule<MainActivity> mActivityRule

    = new ActivityTestRule<>(MainActivity.class); @Test @FlakyTest public void testAddFlexItem() { MainActivity activity = mActivityRule.getActivity(); FlexboxLayout flexboxLayout = (FlexboxLayout) activity.findViewById(R.id.flexbox_layout); assertNotNull(flexboxLayout); int beforeCount = flexboxLayout.getChildCount(); onView(withId(R.id.add_fab)).perform(click()); assertThat(flexboxLayout.getChildCount(), is(beforeCount + 1)); } }
  11. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EditText et

    = (EditText) findViewById(R.id.editText); EditText et2 = (EditText) findViewById(R.id.editText2); Button bt = (Button) findViewById(R.id.button); Button bt2 = (Button) findViewById(R.id.button2); }
  12. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EditText et

    = (EditText) findViewById(R.id.editText); EditText et2 = (EditText) findViewById(R.id.editText2); Button bt = (Button) findViewById(R.id.button); Button bt2 = (Button) findViewById(R.id.button2); }
  13. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.login_activity); EditText usernameField

    = (EditText) findViewById(R.id.login_username); EditText passwordField = (EditText) findViewById(R.id.login_password); Button loginButton = (Button) findViewById(R.id.login_button); Button facebookButton = (Button) findViewById(R.id.login_facebook_button); }
  14. Convenciones ▪ Views vs variables (usernameView vs username as String)

    ▪ Field, View, Button, Pager, List, Grid, etc. ▪ usernameEditText o usernameTextInputLayout? ▪ Ids con namespaces (login_username, login_button, login_something, etc) Dime tu intención y donde estás actuando...
  15. API

  16. @Override protected void onCreate(Bundle savedInstanceState) { ... usernameField.addTextChangedListener(new TextWatcher() {

    @Override public void beforeTextChanged(CharSequence s, int start, int count, int after){ username = s.toString(); check(); } ... }); passwordField.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after){ password = s.toString(); check(); } ... }); } private void check() { if(!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) loginButton.setEnabled(true); }
  17. @Override protected void onCreate(Bundle savedInstanceState) { ... usernameField.onChanged(username -> check(username,

    passwordField.content())); passwordField.onChanged(password -> check(usernameField.content(), password)); } private void check(String username, String password) { if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) loginButton.setEnabled(true); }
  18. “ Las arquitecturas te ayudan a separar tu lógica de

    negocio de la presentación, pero, ¿Qué pasa con todo el código de la UI?
  19. XML

  20. <resources> <string name="login_username_field">...</string> <string name="login_password_field">...</string> <dimen name="login_title_margin_top">...</dimen> <style name="AppTheme.Login"/> <style

    name="AppTheme.Login.Field">...</style> <style name="AppTheme.Login.Button" parent="AppTheme.Common.Button">...</style> <style name="AppTheme.Login.Message">...</style> <style name="AppTheme.Login.Title">...</style> </resources>
  21. <resources> <string name="login_username_field">...</string> <string name="login_password_field">...</string> <dimen name="login_title_margin_top">...</dimen> <style name="AppTheme.Login"/> <style

    name="AppTheme.Login.Field">...</style> <style name="AppTheme.Login.Button">...</style> <style name="AppTheme.Login.Message">...</style> <style name="AppTheme.Login.Title">...</style> </resources>
  22. public class TextField extends android.support.v7.widget.AppCompatEditText { interface Before { void

    changed(String s); } interface On { void changed(String s); } interface After { void changed(String s); } private Before before; private On on; private After after; }
  23. public class TextField extends android.support.v7.widget.AppCompatEditText { public TextField(Context context, AttributeSet

    attrs) { super(context, attrs); addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { if (before != null) before.changed(content()); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (on != null) on.changed(content()); } @Override public void afterTextChanged(Editable s) { if (after != null) after.changed(content()); } }); } }
  24. Events ▪ RxBinding subscibe/unsubscribe ▪ Custom events ayudan a limpiar

    tu codigo, liberan la dependencia directa a los cambios de API.