Навигация в android без боли и слез

73
Навигация без боли и слез Константин Цховребов Android Team Leader

Upload: mobileup

Post on 10-Feb-2017

131 views

Category:

Mobile


9 download

TRANSCRIPT

Page 1: Навигация в Android без боли и слез

Навигация без боли и слез

Константин Цховребов Android Team Leader

Page 2: Навигация в Android без боли и слез
Page 3: Навигация в Android без боли и слез

Первый большой проект на MVP

Page 4: Навигация в Android без боли и слез

В теории все прекрасно!

Первый большой проект на MVP

Page 5: Навигация в Android без боли и слез

В теории все прекрасно!

Первый большой проект на MVP На практике встречаешь ANDROID

Page 6: Навигация в Android без боли и слез

Навигация в андроид приложении

Page 7: Навигация в Android без боли и слез

Навигация в андроид приложении

●  Переход между экранами

Page 8: Навигация в Android без боли и слез

Навигация в андроид приложении

●  Переход между экранами ●  Экраны сменяются в некотором контейнере

Page 9: Навигация в Android без боли и слез

Навигация в андроид приложении

●  Переход между экранами ●  Экраны сменяются в некотором контейнере ●  Для совершения перехода нужен Context

Page 10: Навигация в Android без боли и слез

А что если Fragment сделать презентером?

Page 11: Навигация в Android без боли и слез

А что если Fragment сделать презентером? 1.  Lifecycle

Page 12: Навигация в Android без боли и слез

А что если Fragment сделать презентером? 1.  Lifecycle

2.  Нужен универсальный подход (Activity/Fragment/View)

Page 13: Навигация в Android без боли и слез

А что если Fragment сделать презентером? 1.  Lifecycle

2.  Нужен универсальный подход (Activity/Fragment/View)

3.  Context (и другие классы)

Page 14: Навигация в Android без боли и слез

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

Page 15: Навигация в Android без боли и слез

Готовые решения

Flow (https://github.com/square/flow) Conductor (https://github.com/bluelinelabs/Conductor)

Page 16: Навигация в Android без боли и слез

Требования к идеальной навигации

Page 17: Навигация в Android без боли и слез

Требования к идеальной навигации

●  прямой доступ из презентера

Page 18: Навигация в Android без боли и слез

Требования к идеальной навигации

●  прямой доступ из презентера ●  не завязана на фрагменты

Page 19: Навигация в Android без боли и слез

Требования к идеальной навигации

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк

Page 20: Навигация в Android без боли и слез

Требования к идеальной навигации

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы

Page 21: Навигация в Android без боли и слез

Требования к идеальной навигации

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении

Page 22: Навигация в Android без боли и слез

Требования к идеальной навигации

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов

Page 23: Навигация в Android без боли и слез

Требования к идеальной навигации

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

Page 24: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

Page 25: Навигация в Android без боли и слез

Это реальный проект!

Page 26: Навигация в Android без боли и слез

Команды переходов

Page 27: Навигация в Android без боли и слез

Команды переходов Forward(String screenKey, Object transitionData);

Page 28: Навигация в Android без боли и слез

Команды переходов Forward(String screenKey, Object transitionData);

Back();

Page 29: Навигация в Android без боли и слез

Команды переходов Forward(String screenKey, Object transitionData);

Back();

BackTo(String screenKey);

Page 30: Навигация в Android без боли и слез

Команды переходов Forward(String screenKey, Object transitionData);

Back();

BackTo(String screenKey);

Replace(String screenKey, Object transitionData);

Page 31: Навигация в Android без боли и слез

SystemMessage

SystemMessage(String message);

Page 32: Навигация в Android без боли и слез

Navigator public interface Navigator { void applyCommand(Command command); }

Page 33: Навигация в Android без боли и слез

Navigator public interface Navigator { void applyCommand(Command command); }

public class MainActivity extends Activity { private Navigator navigator = new Navigator() { @Override public void applyCommand(Command command) { ... } } }

Page 34: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

Page 35: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

Page 36: Навигация в Android без боли и слез

public class Presenter { @Inject Navigator navigator; private void next() { navigator.applyCommand(new Forward(“Some screen”)); } }

Page 37: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

Page 38: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

Page 39: Навигация в Android без боли и слез
Page 40: Навигация в Android без боли и слез
Page 41: Навигация в Android без боли и слез

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

Page 42: Навигация в Android без боли и слез

Router public class Router extends BaseRouter { void newRootScreenWithMessage(String screenKey, Object data, String message) {...} }

Page 43: Навигация в Android без боли и слез

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

Page 44: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

Page 45: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

Page 46: Навигация в Android без боли и слез

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

Page 47: Навигация в Android без боли и слез

public class MainActivity extends Activity { @Override protected void onResume() { super.onResume(); router.setNavigator(navigator); } @Override protected void onPause() { super.onPause(); router.removeNavigator(); } }

Page 48: Навигация в Android без боли и слез

Presenter View load()

Page 49: Навигация в Android без боли и слез

View Presenter load()

request()

Page 50: Навигация в Android без боли и слез

Presenter

request()

View

Page 51: Навигация в Android без боли и слез

Presenter

request() response()

View

Page 52: Навигация в Android без боли и слез

Presenter

Router

request() response()

View

Page 53: Навигация в Android без боли и слез

Presenter

RouterImpl Command

Queue

request() response()

View

Page 54: Навигация в Android без боли и слез

View Presenter

RouterImpl Command

Queue

request() response()

Page 55: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

Page 56: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

Page 57: Навигация в Android без боли и слез

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

Page 58: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

Page 59: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

✓ ✓

Page 60: Навигация в Android без боли и слез

Расширение возможностей

●  в большинстве случаев достаточно добавить метод в Router и реализовать его с помощью Command

●  реже необходимо создать новую Command

Page 61: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

✓ ✓

Page 62: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

✓ ✓ ✓

Page 63: Навигация в Android без боли и слез

//TODO:

●  прямой доступ из презентера ●  не завязана на фрагменты ●  не фреймворк ●  короткие вызовы ●  легка в расширении ●  приспособлена для тестов ●  не зависит от жизненного цикла!

✓ ✓

✓ ✓ ✓

Page 64: Навигация в Android без боли и слез

Cicerone Чичероне - (устар.) гид для иностранцев

https://github.com/terrakok/Cicerone repositories { maven { url 'https://dl.bintray.com/terrakok/terramaven/' } } dependencies { //Cicerone compile 'ru.terrakok.cicerone:cicerone:1.0' }

Page 65: Навигация в Android без боли и слез
Page 66: Навигация в Android без боли и слез

Для кого мы ее создали?

Page 67: Навигация в Android без боли и слез

Для кого мы ее создали? Для себя :)

Page 68: Навигация в Android без боли и слез

Для кого мы ее создали?

Почему она может пригодиться вам?

Для себя :)

Page 69: Навигация в Android без боли и слез

Для кого мы ее создали?

●  В приложении нелинейная навигация

Почему она может пригодиться вам?

Для себя :)

Page 70: Навигация в Android без боли и слез

Для кого мы ее создали?

●  В приложении нелинейная навигация ●  Отделение логики от отображения

Почему она может пригодиться вам?

Для себя :)

Page 71: Навигация в Android без боли и слез

Для кого мы ее создали?

●  В приложении нелинейная навигация ●  Отделение логики от отображения ●  Сохранение вызовов навигации после возвращения к приложению

Почему она может пригодиться вам?

Для себя :)

Page 72: Навигация в Android без боли и слез

Возможности 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 {}

Page 73: Навигация в Android без боли и слез

Спасибо за внимание! Вопросы?

email: [email protected] telegram: @terrakok https://github.com/terrakok/Cicerone