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

Cicerone. Android screen navigation

Avatar for terrakok terrakok
December 27, 2016

Cicerone. Android screen navigation

Avatar for terrakok

terrakok

December 27, 2016
Tweet

More Decks by terrakok

Other Decks in Programming

Transcript

  1. Навигация в андроид приложении • Переход между экранами • Экраны

    сменяются в некотором контейнере • Для совершения перехода нужен Context
  2. А что если Fragment сделать презентером? 1. Lifecycle 2. Нужен

    универсальный подход (Activity/Fragment/View)
  3. А что если Fragment сделать презентером? 1. Lifecycle 2. Нужен

    универсальный подход (Activity/Fragment/View) 3. Context (и другие классы)
  4. Mosby (http://hannesdorfmann.com/mosby/) public interface LoginView extends MvpView { public void

    showLoginForm(); public void showError(); public void showLoading(); public void loginSuccessful(); } public class LoginFragment … implements LoginView { … // Called when login was successful @Override public void loginSuccessful() { getActivity().finish(); } … }
  5. Требования к идеальной навигации • прямой доступ из презентера •

    не завязана на фрагменты • не фреймворк • короткие вызовы
  6. Требования к идеальной навигации • прямой доступ из презентера •

    не завязана на фрагменты • не фреймворк • короткие вызовы • легка в расширении
  7. Требования к идеальной навигации • прямой доступ из презентера •

    не завязана на фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов
  8. Требования к идеальной навигации • прямой доступ из презентера •

    не завязана на фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла!
  9. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла!
  10. Navigator public interface Navigator { void applyCommand(Command command); } public

    class MainActivity extends Activity { private Navigator navigator = new Navigator() { @Override public void applyCommand(Command command) { ... } } }
  11. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла!
  12. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓
  13. public class Presenter { @Inject Navigator navigator; private void next()

    { navigator.applyCommand(new Forward(“Some screen”)); } }
  14. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓
  15. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓
  16. public class Presenter { @Inject Navigator navigator; private void authError()

    { navigator.applyCommand(new BackTo(null)); navigator.applyCommand(new Replace("Login screen", null)); navigator.applyCommand(new SystemMessage("Token expired!")); } }
  17. Router public class Router extends BaseRouter { void newRootScreenWithMessage(String screenKey,

    Object data, String message) {...} } public class Presenter { @Inject Router router; private void authError() { router.newRootScreenWithMessage("Login screen", null, "Token expired!"); } }
  18. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓
  19. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓
  20. public class Router extends BaseRouter { private Navigator navigator; public

    void setNavigator(Navigator navigator) { this.navigator = navigator; } public void removeNavigator() { this.navigator = null; } public void newRootScreenWithMessage(String screenKey, Object data, String message) { if (navigator != null) { navigator.applyCommand(new BackTo(null)); navigator.applyCommand(new Replace("Login screen", null)); navigator.applyCommand(new SystemMessage("Token expired!")); } } }
  21. public class MainActivity extends Activity { @Override protected void onResume()

    { super.onResume(); router.setNavigator(navigator); } @Override protected void onPause() { super.onPause(); router.removeNavigator(); } }
  22. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓
  23. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓ ✓
  24. Unit тестирование @Test public void someTest() throws Exception { Router

    mockRouter = mock(Router.class); Presenter presenter = new Presenter(); presenter.onNextButtonClicked(); verify(mockRouter, times(1)).navigateTo( eq("Some screen"), argument.capture() ); }
  25. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓ ✓
  26. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓ ✓ ✓
  27. Расширение возможностей • в большинстве случаев достаточно добавить метод в

    Router и реализовать его с помощью Command • реже необходимо создать новую Command
  28. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓ ✓ ✓
  29. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓ ✓ ✓ ✓
  30. //TODO: • прямой доступ из презентера • не завязана на

    фрагменты • не фреймворк • короткие вызовы • легка в расширении • приспособлена для тестов • не зависит от жизненного цикла! ✓ ✓ ✓ ✓ ✓ ✓ ✓
  31. Cicerone Чичероне - (устар.) гид для иностранцев https://github.com/terrakok/Cicerone repositories {

    maven { url 'https://dl.bintray.com/terrakok/terramaven/' } } dependencies { //Cicerone compile 'ru.terrakok.cicerone:cicerone:1.0' }
  32. Для кого мы ее создали? • В приложении нелинейная навигация

    Почему она может пригодиться вам? Для себя :)
  33. Для кого мы ее создали? • В приложении нелинейная навигация

    • Отделение логики от отображения Почему она может пригодиться вам? Для себя :)
  34. Для кого мы ее создали? • В приложении нелинейная навигация

    • Отделение логики от отображения • Сохранение вызовов навигации после возвращения к приложению Почему она может пригодиться вам? Для себя :)
  35. Возможности Cicerone public class Router extends BaseRouter { void navigateTo(String

    screenKey, Object data); void newScreenChain(String screenKey, Object data); void newRootScreen(String screenKey, Object data); void replaceScreen(String screenKey, Object data); void backTo(String screenKey); void exit(); void exitWithMessage(String message); void showSystemMessage(String message); } public abstract class FragmentNavigator implements Navigator {}