SlideShare uma empresa Scribd logo
1 de 61
1
Определить Presenter
Определить интерфейсView
РеализоватьView
Выделить бизнес-логику в Model
2
Автоматическое сохранение отображения при пересозданииView
Никакого boilerplate-кода
Отсутствие ненужных флажков, id, switch-case, e.t.c.
3
ViewImpl Presenter
ViewState
ViewCommands
4
ViewImpl Presenter
ViewState
ViewCommands
Command
5
ViewImpl Presenter
ViewState
ViewCommands
CommandCommand
6
ViewImpl Presenter
ViewState
ViewCommands
Command
Command
7
ViewImpl Presenter
ViewState
ViewCommands
Command
Command
8
ViewImpl Presenter
ViewState
ViewCommands
Command
9
ViewImpl Presenter
ViewState
ViewCommands
CommandCommand
10
Приложение запускается
Проходит 1 секунда
Отображается сообщение
11
public interface HelloWorldView extends MvpView {
void showMessage(int message);
}
12
@InjectViewState
public class HelloWorldPresenter extends MvpPresenter<HelloWorldView> {
public HelloWorldPresenter() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
sleepSecond();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
getViewState().showMessage(R.string.hello_world);
}
}.execute();
...
13
public class MainActivity extends MvpAppCompatActivity implements HelloWorldView
{
@InjectPresenter
HelloWorldPresenter mHelloWorldPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void showMessage(int message) {
TextView messageTextView = new TextView(this);
messageTextView.setText(message);
((ViewGroup) findViewById(R.id.activity_main)).addView(messageTextView);
}
}
14
15
Приложение запускается
Проходит 5 секунд
На экране отображается количество оставшихся секунд
Отображается сообщение
16
@InjectViewState
public class HelloWorldPresenter extends MvpPresenter<HelloWorldView> {
...
@Override protected void onPreExecute() {
getViewState().showTimer();
}
@Override protected Void doInBackground(Void... voids) {
for (int i = 5; i > 0; i--) {
publishProgress(i);
sleepSecond();
}
return null;
}
@Override protected void onProgressUpdate(Integer... values) {
getViewState().setTimer(values[0]);
}
@Override protected void onPostExecute(Void aVoid) {
getViewState().hideTimer();
getViewState().showMessage(R.string.hello_world);
}
...
17
public interface HelloWorldView extends MvpView {
void showTimer();
void hideTimer();
void setTimer(int seconds);
void showMessage(int message);
}
18
public class MainActivity extends MvpAppCompatActivity implements HelloWorldView
{
private TextView mTimerTextView;
@Override
public void showTimer() {
mTimerTextView.setVisibility(View.VISIBLE);
}
@Override
public void hideTimer() {
mTimerTextView.setVisibility(View.GONE);
}
@Override
public void setTimer(int seconds) {
mTimerTextView.setText(getString(R.string.timer, seconds));
}
19
20
Приложение запускается
Проходит 2 секунды
На экране отображается количество оставшихся секунд
Отображается сообщение в виде AlertDialog
21
public class MainActivity extends MvpAppCompatActivity implements HelloWorldView {
private AlertDialog mMessageDialog;
@Override
public void showMessage(int message) {
mMessageDialog = new AlertDialog.Builder(this)
.setTitle(R.string.app_name).setMessage(message)
.setOnDismissListener(dialog -> mHelloWorldPresenter.onDismissMessage())
.show();
}
@Override
public void hideMessage() {
if (mMessageDialog != null) {
mMessageDialog.dismiss();
}
}
22
public class MainActivity extends MvpAppCompatActivity implements HelloWorldView {
private AlertDialog mMessageDialog;
@Override
public void showMessage(int message) {
mMessageDialog = new AlertDialog.Builder(this)
.setTitle(R.string.app_name).setMessage(message)
.setOnDismissListener(dialog -> mHelloWorldPresenter.onDismissMessage())
.show();
}
@Override
public void hideMessage() {
if (mMessageDialog != null) {
mMessageDialog.dismiss();
}
}
23
06-02 04:59:00.178 14192-14192/com.arellomobile.mvp.sample.appsconf E/WindowManager:
android.view.WindowLeaked: Activity com.arellomobile.mvp.sample. MainActivity has leaked
window DecorView@c59996b[] that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:418)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:331)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at android.app.Dialog.show(Dialog.java:322)
at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:956)
...
24
@Override
protected void onDestroy() {
super.onDestroy();
if (mMessageDialog != null) {
mMessageDialog.dismiss();
}
}
25
@Override
protected void onDestroy() {
super.onDestroy();
if (mMessageDialog != null) {
mMessageDialog.dismiss();
}
}
26
@Override
protected void onDestroy() {
super.onDestroy();
if (mMessageDialog != null) {
mMessageDialog.setOnDismissListener(null);
mMessageDialog.dismiss();
}
}
27
@InjectViewState
public class HelloWorldPresenter extends MvpPresenter<HelloWorldView> {
...
public void onDismissMessage() {
getViewState().hideMessage();
}
}
28
@StateStrategyType(AddToEndSingleStrategy.class)
public interface HelloWorldView extends MvpView {
void showTimer();
void hideTimer();
void setTimer(int seconds);
void showMessage(int message);
void hideMessage();
}
29
30
Приложение запускается
Проходит 5 секунд
На экране отображается количество оставшихся секунд
Отображается сообщение в виде стороннейView
31
public class MainActivity extends MvpAppCompatActivity implements HelloWorldView {
@Override
public void showMessage(int message) {
ViewGroup rootView = (ViewGroup) findViewById(R.id.activity_main);
mMessageView = inflate(R.layout.item_message, rootView, true);
((TextView) mMessageView.findViewById(R.id.message_text_view)).setText(message);
mMessageView.findViewById(R.id.close_button)
.setOnClickListener(v -> mHelloWorldPresenter.onDismissMessage());
}
@Override
public void hideMessage() {
ViewGroup rootView = (ViewGroup) findViewById(R.id.activity_main);
rootView.removeView(mMessageView);
}
32
33
• В Activity отображается 2 Fragment
• Каждый Fragment содержит счётчик нажатий на кнопку
• Изменения показаний счётчика одного фрагмента никак не
влияют на показания счётчика другого фрагмента
34
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.frame_1, getFragment(0xffFF80AB))
.add(R.id.frame_2, getFragment(0xffCCFF90))
.commit();
}
}
private Fragment getFragment(int color) {
CounterFragment fragment = new CounterFragment();
Bundle args = new Bundle();
args.putInt("argColor", color);
fragment.setArguments(args);
return fragment;
}
}
35
@InjectViewState
public class CounterPresenter extends MvpPresenter<CounterView> {
private int mCount;
public CounterPresenter() {
getViewState().showCount(mCount);
}
public void onPlusClick() {
mCount++;
getViewState().showCount(mCount);
}
}
36
public interface CounterView extends MvpView {
@StateStrategyType(AddToEndSingleStrategy.class)
void showCount(int count);
}
37
public class CounterFragment extends MvpAppCompatFragment implements CounterView {
@InjectPresenter
CounterPresenter mCounterPresenter;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
view.findViewById(R.id.plus_button).setOnClickListener(v -> mCounterPresenter.onPlusClick());
}
@Override
public void showCount(int count) {
mCounterTextView.setText(String.valueOf(count));
}
}
38
39
В Activity отображается 2 Fragment
Каждый Fragment содержит счётчик нажатий на кнопку
Показания счётчиков синхронизированы
40
@InjectViewState
public class CounterPresenter extends MvpPresenter<CounterView> {
@Inject
CounterInteractor counterInteractor;
private final Disposable disposable;
public CounterPresenter() {
App.getAppComponent().inject(this);
disposable = counterInteractor.getCounter()
.subscribe(value -> getViewState().showCount(value));
}
public void onPlusClick() {
counterInteractor.increase();
}
@Override
public void onDestroy() {
disposable.dispose();
}
}
41
public class CounterInteractor {
private int counterValue = 0;
private Subject<Integer> counter = BehaviorSubject.createDefault(counterValue);
public Subject<Integer> getCounter() {
return counter;
}
public void increase() {
counterValue++;
counter.onNext(counterValue);
}
}
42
43
В Activity отображается 2 счётчика
Каждый счётчик является CustomView
Изменения показаний одного счётчика никак не влияют на
показания другого счётчика
44
public class MvpActivity extends Activity {
private MvpDelegate<? extends MvpActivity> mMvpDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getMvpDelegate().onCreate(savedInstanceState);
}
@Override
protected void onStart() {
super.onStart();
getMvpDelegate().onAttach();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getMvpDelegate().onSaveInstanceState(outState);
} 45
46
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getMvpDelegate().onSaveInstanceState(outState);
getMvpDelegate().onDetach();
}
@Override
protected void onStop() {
super.onStop();
getMvpDelegate().onDetach();
}
@Override
protected void onDestroy() {
super.onDestroy();
getMvpDelegate().onDestroyView();
if (isFinishing()) {
getMvpDelegate().onDestroy();
}
}
}
public class MainActivity extends MvpAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
((CounterWidget) findViewById(R.id.counter_1)).init(getMvpDelegate());
((CounterWidget) findViewById(R.id.counter_2)).init(getMvpDelegate());
}
}
47
public class CounterWidget extends FrameLayout implements CounterView {
private MvpDelegate<CounterWidget> mMvpDelegate;
@InjectPresenter
CounterPresenter mCounterPresenter;
public void init(MvpDelegate parentDelegate) {
initMvpDelegate(parentDelegate);
mMvpDelegate.onCreate();
mMvpDelegate.onAttach();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mMvpDelegate.onSaveInstanceState();
mMvpDelegate.onDetach();
}
public void initMvpDelegate() {
mMvpDelegate = new MvpDelegate<>(this);
mMvpDelegate.setParentDelegate(mParentDelegate, String.valueOf(getId()));
}
private TextView mCounterTextView;
public CounterWidget(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.item_counter, this, true);
mCounterTextView = (TextView) findViewById(R.id.count_text);
View button = findViewById(R.id.plus_button);
button.setOnClickListener(view -> mCounterPresenter.onPlusClick());
}
@Override
public void showCount(int count) {
mCounterTextView.setText(String.valueOf(count));
}
48
49
Сделать экран отображения списка новостей
Должен быть SwipeToRefresh
Если произошла ошибка, то показать её как Toast
50
51
@StateStrategyType(AddToEndSingleStrategy.class)
public interface NewsFeedView extends MvpView {
String TAG_LOADING_COMMAND = "tagLoadingCommand";
void showNewsFeed(NewsFeed newsFeed);
@StateStrategyType(OneExecutionStateStrategy.class)
void showError(String message);
@StateStrategyType(value = AddToEndSingleByTagStateStrategy.class, tag = TAG_LOADING_COMMAND)
void startLoading();
@StateStrategyType(value = AddToEndSingleByTagStateStrategy.class, tag = TAG_LOADING_COMMAND)
void finishLoading();
}
52
public class AddToEndSingleByTagStateStrategy implements StateStrategy {
public <View extends MvpView> void beforeApply(List currentState, ViewCommand command) {
Iterator<ViewCommand<View>> iterator = currentState.iterator();
while (iterator.hasNext()) {
ViewCommand<View> entry = iterator.next();
if (entry.getTag().equals(incomingCommand.getTag())) {
iterator.remove();
break;
}
}
currentState.add(incomingCommand);
}
public <View extends MvpView> void afterApply(List currentState, ViewCommand command) {
// pass
}
}
Сделать экран деталей конкретной новости
53
@InjectViewState
public class DetailsPresenter extends MvpPresenter<DetailsView> {
public DetailsPresenter(long newsId) {
getViewState().showDetails("Details of "" + newsId + """);
}
}
public interface DetailsView extends MvpView {
void showDetails(String details);
}
54
public class DetailsActivity extends MvpAppCompatActivity implements DetailsView {
@InjectPresenter
DetailsPresenter mDetailsPresenter;
@ProvidePresenter
DetailsPresenter provideDetailsPresenter() {
return new DetailsPresenter(getIntent().getLongExtra("extraDetailsId", 0));
}
@Override
public void showDetails(String details) {
Log.i(DetailsActivity.class.getSimpleName(), details);
}
}
55
0. Annotation processor: Generate PresenterFields
1. MvpDelegate: onCreate(savedInstanceState)
2. MvpDelegate: Init delegate tag
3. MvpProcessor: Collect all PresenterField for MvpDelegate
4. MvpProcessor: Init each PresenterField
1. MvpProcessor: Generate presenter tag
2. PresenterStore: Get MvpPresenter by type and tag
3. MvpProcessor: MvpPresenter exists?
1. True:
1. MvpProcessor: Init presenter field of Delegated
2. False:
1. PresenterField: Provide presenter
2. PresenterStore: Save presenter
3. MvpProcessor: Init presenter field of Delegated
56
0. Annotation processor: Generate ViewState
1. MvpPresenter: Construct
2. Binder: Bind presenter
3. Binder: Find ViewState for MvpPresenter
4. Binder: Create ViewState
5. Binder: Set ViewState to MvpPresenter
57
1. MvpPresenter: Send command
2. ViewState: Instantiation of ViewCommand
3. ViewState: Get StateStrategy of ViewCommand
4. StateStrategy: Called beforeApply(currentState, incomingCommand)
5. ViewState: Have a Views?
1. False: –
2. True:
1. ViewCommand: Apply to each Views
2. StateStrategy: Called afterApply(currentState, incomingState)
6. ViewState: Attached View
7. ViewState: Apply each ViewCommands
1. ViewCommand: Apply to attached View
2. StateStrategy: Called afterApply(currentState, incomingState)
58
59
1. Нет проблем с жизненным циклом
2. Boilerplate-code генерируется в compile time
3. Можно использовать несколько Presenter в одном месте
4. Можно любой компонент превратить в MvpView
Присоединяйтесь к проекту на github.com!
PS: https://github.com/senneco/MoxyCases
60
61

Mais conteúdo relacionado

Mais procurados

Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программированиеDenis Tsvettsih
 
Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus Denis Tsvettsih
 
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...Mail.ru Group
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Sigma Software
 
Dependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInjectDependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInjectakrakovetsky
 
Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...
Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...
Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...Dakiry
 
Архитектура. Доступноять программных систем.
Архитектура. Доступноять программных систем.Архитектура. Доступноять программных систем.
Архитектура. Доступноять программных систем.Dima Dzuba
 
Unit tests final
Unit tests finalUnit tests final
Unit tests finalcorehard_by
 
Веселая ферма. Соседи.
Веселая ферма. Соседи.Веселая ферма. Соседи.
Веселая ферма. Соседи.Doomer Samoiloff
 
C# Web. Занятие 11.
C# Web. Занятие 11.C# Web. Занятие 11.
C# Web. Занятие 11.Igor Shkulipa
 
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersШкола-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersГлеб Тарасов
 
Клиент-серверное взаимодействие под android в деталях
Клиент-серверное взаимодействие под android в деталяхКлиент-серверное взаимодействие под android в деталях
Клиент-серверное взаимодействие под android в деталяхKirill Zotin
 
AndroidMVPHelper
AndroidMVPHelperAndroidMVPHelper
AndroidMVPHelperDataArt
 
Юнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, GoogleЮнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, Googleyaevents
 
Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...metaform
 
Лекция Android. Хранение данных
Лекция Android. Хранение данныхЛекция Android. Хранение данных
Лекция Android. Хранение данныхАлександр Брич
 
Лекция Android. БД SQLite, ContentProvider, Loader
Лекция Android. БД SQLite, ContentProvider, LoaderЛекция Android. БД SQLite, ContentProvider, Loader
Лекция Android. БД SQLite, ContentProvider, LoaderАлександр Брич
 
MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)GoSharp
 
Паттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложенийПаттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложенийGoSharp
 
МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4Dima Dzuba
 

Mais procurados (20)

Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программирование
 
Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus
 
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
«Buzzwords everywhere, или Борьба с ветряными мельницами», Артём Дроздов, Mai...
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
 
Dependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInjectDependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInject
 
Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...
Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...
Олексій Стульніков “WinAppDriver – автоматизація Desktop ніколи не була такою...
 
Архитектура. Доступноять программных систем.
Архитектура. Доступноять программных систем.Архитектура. Доступноять программных систем.
Архитектура. Доступноять программных систем.
 
Unit tests final
Unit tests finalUnit tests final
Unit tests final
 
Веселая ферма. Соседи.
Веселая ферма. Соседи.Веселая ферма. Соседи.
Веселая ферма. Соседи.
 
C# Web. Занятие 11.
C# Web. Занятие 11.C# Web. Занятие 11.
C# Web. Занятие 11.
 
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, ControllersШкола-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
Школа-студия разработки приложений для iOS. 2 лекция. MVC, View, Controllers
 
Клиент-серверное взаимодействие под android в деталях
Клиент-серверное взаимодействие под android в деталяхКлиент-серверное взаимодействие под android в деталях
Клиент-серверное взаимодействие под android в деталях
 
AndroidMVPHelper
AndroidMVPHelperAndroidMVPHelper
AndroidMVPHelper
 
Юнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, GoogleЮнит-тестирование и Google Mock. Влад Лосев, Google
Юнит-тестирование и Google Mock. Влад Лосев, Google
 
Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...
 
Лекция Android. Хранение данных
Лекция Android. Хранение данныхЛекция Android. Хранение данных
Лекция Android. Хранение данных
 
Лекция Android. БД SQLite, ContentProvider, Loader
Лекция Android. БД SQLite, ContentProvider, LoaderЛекция Android. БД SQLite, ContentProvider, Loader
Лекция Android. БД SQLite, ContentProvider, Loader
 
MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)MVVM в WinForms – DevExpress Way (теория и практика)
MVVM в WinForms – DevExpress Way (теория и практика)
 
Паттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложенийПаттерны быстрой разработки WPF MVVM бизнес-приложений
Паттерны быстрой разработки WPF MVVM бизнес-приложений
 
МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4МАИ, Сети ЭВМ, Лекция №4
МАИ, Сети ЭВМ, Лекция №4
 

Semelhante a Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)

"Погружение в Robolectric" Дмитрий Костырев (Avito)
"Погружение в Robolectric"  Дмитрий Костырев (Avito)"Погружение в Robolectric"  Дмитрий Костырев (Avito)
"Погружение в Robolectric" Дмитрий Костырев (Avito)AvitoTech
 
Разбираемся с CoordinatorLayout
Разбираемся с CoordinatorLayoutРазбираемся с CoordinatorLayout
Разбираемся с CoordinatorLayoutRambler Android
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
 
Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...
Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...
Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...Mail.ru Group
 
Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011Dmytro Mindra
 
RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)Noveo
 
Кирилл Харьков
Кирилл ХарьковКирилл Харьков
Кирилл ХарьковCodeFest
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5Technopark
 
Аспектно-Ориентированный Подход
Аспектно-Ориентированный ПодходАспектно-Ориентированный Подход
Аспектно-Ориентированный Подходakopium
 
Коротко о React.js
Коротко о React.jsКоротко о React.js
Коротко о React.jsMad Devs
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокAndrey Karpov
 
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 27bits
 
Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур
 Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур  Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур
Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур it-people
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationAndrii Dzynia
 
Школа-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. РазноеШкола-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. РазноеГлеб Тарасов
 
Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016
Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016
Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016РИФ-Воронеж
 

Semelhante a Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile) (20)

Паттерны проектирования
Паттерны проектированияПаттерны проектирования
Паттерны проектирования
 
"Погружение в Robolectric" Дмитрий Костырев (Avito)
"Погружение в Robolectric"  Дмитрий Костырев (Avito)"Погружение в Robolectric"  Дмитрий Костырев (Avito)
"Погружение в Robolectric" Дмитрий Костырев (Avito)
 
Разбираемся с CoordinatorLayout
Разбираемся с CoordinatorLayoutРазбираемся с CoordinatorLayout
Разбираемся с CoordinatorLayout
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
Android service
Android serviceAndroid service
Android service
 
Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...
Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...
Droidcon Moscow 2015. Dagger2 практический ликбез по работе с кинжалами. Дмит...
 
Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011
 
RoboGuice
RoboGuiceRoboGuice
RoboGuice
 
RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)
 
Кирилл Харьков
Кирилл ХарьковКирилл Харьков
Кирилл Харьков
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5
 
Аспектно-Ориентированный Подход
Аспектно-Ориентированный ПодходАспектно-Ориентированный Подход
Аспектно-Ориентированный Подход
 
Коротко о React.js
Коротко о React.jsКоротко о React.js
Коротко о React.js
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
 
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
Спецкурс "Современные практики разработки ПО", 2013-2014 уч. год, занятие 2
 
Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур
 Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур  Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур
Xamarin: кроссплатформенные грабли, Дмитрий Моисеев, СКБ Контур
 
Aspect Oriented Approach
Aspect Oriented ApproachAspect Oriented Approach
Aspect Oriented Approach
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test Automation
 
Школа-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. РазноеШкола-Студия разработки приложений для iOS. 5 лекция. Разное
Школа-Студия разработки приложений для iOS. 5 лекция. Разное
 
Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016
Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016
Денис Неклюдов. Держи свое приложение на волне новинок. РИФ-Воронеж 2016
 

Mais de Ontico

One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...Ontico
 
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Масштабируя DNS / Артем Гавриченков (Qrator Labs)Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Масштабируя DNS / Артем Гавриченков (Qrator Labs)Ontico
 
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)Ontico
 
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Ontico
 
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...Ontico
 
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)Ontico
 
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...Ontico
 
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...Ontico
 
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)Ontico
 
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)Ontico
 
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...Ontico
 
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...Ontico
 
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...Ontico
 
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)Ontico
 
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)Ontico
 
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)Ontico
 
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)Ontico
 
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
100500 способов кэширования в Oracle Database или как достичь максимальной ск...100500 способов кэширования в Oracle Database или как достичь максимальной ск...
100500 способов кэширования в Oracle Database или как достичь максимальной ск...Ontico
 
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...Ontico
 
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...Ontico
 

Mais de Ontico (20)

One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
 
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Масштабируя DNS / Артем Гавриченков (Qrator Labs)Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
 
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
 
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
 
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
 
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
 
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
 
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
 
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
 
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)MySQL Replication — Advanced Features / Петр Зайцев (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
 
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
 
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
 
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
 
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
 
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
 
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
 
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
 
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
100500 способов кэширования в Oracle Database или как достичь максимальной ск...100500 способов кэширования в Oracle Database или как достичь максимальной ск...
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
 
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
 
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
 

Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)

  • 1. 1
  • 3. Автоматическое сохранение отображения при пересозданииView Никакого boilerplate-кода Отсутствие ненужных флажков, id, switch-case, e.t.c. 3
  • 11. Приложение запускается Проходит 1 секунда Отображается сообщение 11
  • 12. public interface HelloWorldView extends MvpView { void showMessage(int message); } 12
  • 13. @InjectViewState public class HelloWorldPresenter extends MvpPresenter<HelloWorldView> { public HelloWorldPresenter() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... voids) { sleepSecond(); return null; } @Override protected void onPostExecute(Void aVoid) { getViewState().showMessage(R.string.hello_world); } }.execute(); ... 13
  • 14. public class MainActivity extends MvpAppCompatActivity implements HelloWorldView { @InjectPresenter HelloWorldPresenter mHelloWorldPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void showMessage(int message) { TextView messageTextView = new TextView(this); messageTextView.setText(message); ((ViewGroup) findViewById(R.id.activity_main)).addView(messageTextView); } } 14
  • 15. 15
  • 16. Приложение запускается Проходит 5 секунд На экране отображается количество оставшихся секунд Отображается сообщение 16
  • 17. @InjectViewState public class HelloWorldPresenter extends MvpPresenter<HelloWorldView> { ... @Override protected void onPreExecute() { getViewState().showTimer(); } @Override protected Void doInBackground(Void... voids) { for (int i = 5; i > 0; i--) { publishProgress(i); sleepSecond(); } return null; } @Override protected void onProgressUpdate(Integer... values) { getViewState().setTimer(values[0]); } @Override protected void onPostExecute(Void aVoid) { getViewState().hideTimer(); getViewState().showMessage(R.string.hello_world); } ... 17
  • 18. public interface HelloWorldView extends MvpView { void showTimer(); void hideTimer(); void setTimer(int seconds); void showMessage(int message); } 18
  • 19. public class MainActivity extends MvpAppCompatActivity implements HelloWorldView { private TextView mTimerTextView; @Override public void showTimer() { mTimerTextView.setVisibility(View.VISIBLE); } @Override public void hideTimer() { mTimerTextView.setVisibility(View.GONE); } @Override public void setTimer(int seconds) { mTimerTextView.setText(getString(R.string.timer, seconds)); } 19
  • 20. 20
  • 21. Приложение запускается Проходит 2 секунды На экране отображается количество оставшихся секунд Отображается сообщение в виде AlertDialog 21
  • 22. public class MainActivity extends MvpAppCompatActivity implements HelloWorldView { private AlertDialog mMessageDialog; @Override public void showMessage(int message) { mMessageDialog = new AlertDialog.Builder(this) .setTitle(R.string.app_name).setMessage(message) .setOnDismissListener(dialog -> mHelloWorldPresenter.onDismissMessage()) .show(); } @Override public void hideMessage() { if (mMessageDialog != null) { mMessageDialog.dismiss(); } } 22
  • 23. public class MainActivity extends MvpAppCompatActivity implements HelloWorldView { private AlertDialog mMessageDialog; @Override public void showMessage(int message) { mMessageDialog = new AlertDialog.Builder(this) .setTitle(R.string.app_name).setMessage(message) .setOnDismissListener(dialog -> mHelloWorldPresenter.onDismissMessage()) .show(); } @Override public void hideMessage() { if (mMessageDialog != null) { mMessageDialog.dismiss(); } } 23
  • 24. 06-02 04:59:00.178 14192-14192/com.arellomobile.mvp.sample.appsconf E/WindowManager: android.view.WindowLeaked: Activity com.arellomobile.mvp.sample. MainActivity has leaked window DecorView@c59996b[] that was originally added here at android.view.ViewRootImpl.<init>(ViewRootImpl.java:418) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:331) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93) at android.app.Dialog.show(Dialog.java:322) at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:956) ... 24
  • 25. @Override protected void onDestroy() { super.onDestroy(); if (mMessageDialog != null) { mMessageDialog.dismiss(); } } 25
  • 26. @Override protected void onDestroy() { super.onDestroy(); if (mMessageDialog != null) { mMessageDialog.dismiss(); } } 26
  • 27. @Override protected void onDestroy() { super.onDestroy(); if (mMessageDialog != null) { mMessageDialog.setOnDismissListener(null); mMessageDialog.dismiss(); } } 27
  • 28. @InjectViewState public class HelloWorldPresenter extends MvpPresenter<HelloWorldView> { ... public void onDismissMessage() { getViewState().hideMessage(); } } 28
  • 29. @StateStrategyType(AddToEndSingleStrategy.class) public interface HelloWorldView extends MvpView { void showTimer(); void hideTimer(); void setTimer(int seconds); void showMessage(int message); void hideMessage(); } 29
  • 30. 30
  • 31. Приложение запускается Проходит 5 секунд На экране отображается количество оставшихся секунд Отображается сообщение в виде стороннейView 31
  • 32. public class MainActivity extends MvpAppCompatActivity implements HelloWorldView { @Override public void showMessage(int message) { ViewGroup rootView = (ViewGroup) findViewById(R.id.activity_main); mMessageView = inflate(R.layout.item_message, rootView, true); ((TextView) mMessageView.findViewById(R.id.message_text_view)).setText(message); mMessageView.findViewById(R.id.close_button) .setOnClickListener(v -> mHelloWorldPresenter.onDismissMessage()); } @Override public void hideMessage() { ViewGroup rootView = (ViewGroup) findViewById(R.id.activity_main); rootView.removeView(mMessageView); } 32
  • 33. 33
  • 34. • В Activity отображается 2 Fragment • Каждый Fragment содержит счётчик нажатий на кнопку • Изменения показаний счётчика одного фрагмента никак не влияют на показания счётчика другого фрагмента 34
  • 35. public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.frame_1, getFragment(0xffFF80AB)) .add(R.id.frame_2, getFragment(0xffCCFF90)) .commit(); } } private Fragment getFragment(int color) { CounterFragment fragment = new CounterFragment(); Bundle args = new Bundle(); args.putInt("argColor", color); fragment.setArguments(args); return fragment; } } 35
  • 36. @InjectViewState public class CounterPresenter extends MvpPresenter<CounterView> { private int mCount; public CounterPresenter() { getViewState().showCount(mCount); } public void onPlusClick() { mCount++; getViewState().showCount(mCount); } } 36
  • 37. public interface CounterView extends MvpView { @StateStrategyType(AddToEndSingleStrategy.class) void showCount(int count); } 37
  • 38. public class CounterFragment extends MvpAppCompatFragment implements CounterView { @InjectPresenter CounterPresenter mCounterPresenter; @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { view.findViewById(R.id.plus_button).setOnClickListener(v -> mCounterPresenter.onPlusClick()); } @Override public void showCount(int count) { mCounterTextView.setText(String.valueOf(count)); } } 38
  • 39. 39
  • 40. В Activity отображается 2 Fragment Каждый Fragment содержит счётчик нажатий на кнопку Показания счётчиков синхронизированы 40
  • 41. @InjectViewState public class CounterPresenter extends MvpPresenter<CounterView> { @Inject CounterInteractor counterInteractor; private final Disposable disposable; public CounterPresenter() { App.getAppComponent().inject(this); disposable = counterInteractor.getCounter() .subscribe(value -> getViewState().showCount(value)); } public void onPlusClick() { counterInteractor.increase(); } @Override public void onDestroy() { disposable.dispose(); } } 41
  • 42. public class CounterInteractor { private int counterValue = 0; private Subject<Integer> counter = BehaviorSubject.createDefault(counterValue); public Subject<Integer> getCounter() { return counter; } public void increase() { counterValue++; counter.onNext(counterValue); } } 42
  • 43. 43
  • 44. В Activity отображается 2 счётчика Каждый счётчик является CustomView Изменения показаний одного счётчика никак не влияют на показания другого счётчика 44
  • 45. public class MvpActivity extends Activity { private MvpDelegate<? extends MvpActivity> mMvpDelegate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getMvpDelegate().onCreate(savedInstanceState); } @Override protected void onStart() { super.onStart(); getMvpDelegate().onAttach(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); getMvpDelegate().onSaveInstanceState(outState); } 45
  • 46. 46 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); getMvpDelegate().onSaveInstanceState(outState); getMvpDelegate().onDetach(); } @Override protected void onStop() { super.onStop(); getMvpDelegate().onDetach(); } @Override protected void onDestroy() { super.onDestroy(); getMvpDelegate().onDestroyView(); if (isFinishing()) { getMvpDelegate().onDestroy(); } } }
  • 47. public class MainActivity extends MvpAppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main3); ((CounterWidget) findViewById(R.id.counter_1)).init(getMvpDelegate()); ((CounterWidget) findViewById(R.id.counter_2)).init(getMvpDelegate()); } } 47
  • 48. public class CounterWidget extends FrameLayout implements CounterView { private MvpDelegate<CounterWidget> mMvpDelegate; @InjectPresenter CounterPresenter mCounterPresenter; public void init(MvpDelegate parentDelegate) { initMvpDelegate(parentDelegate); mMvpDelegate.onCreate(); mMvpDelegate.onAttach(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mMvpDelegate.onSaveInstanceState(); mMvpDelegate.onDetach(); } public void initMvpDelegate() { mMvpDelegate = new MvpDelegate<>(this); mMvpDelegate.setParentDelegate(mParentDelegate, String.valueOf(getId())); } private TextView mCounterTextView; public CounterWidget(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.item_counter, this, true); mCounterTextView = (TextView) findViewById(R.id.count_text); View button = findViewById(R.id.plus_button); button.setOnClickListener(view -> mCounterPresenter.onPlusClick()); } @Override public void showCount(int count) { mCounterTextView.setText(String.valueOf(count)); } 48
  • 49. 49
  • 50. Сделать экран отображения списка новостей Должен быть SwipeToRefresh Если произошла ошибка, то показать её как Toast 50
  • 51. 51 @StateStrategyType(AddToEndSingleStrategy.class) public interface NewsFeedView extends MvpView { String TAG_LOADING_COMMAND = "tagLoadingCommand"; void showNewsFeed(NewsFeed newsFeed); @StateStrategyType(OneExecutionStateStrategy.class) void showError(String message); @StateStrategyType(value = AddToEndSingleByTagStateStrategy.class, tag = TAG_LOADING_COMMAND) void startLoading(); @StateStrategyType(value = AddToEndSingleByTagStateStrategy.class, tag = TAG_LOADING_COMMAND) void finishLoading(); }
  • 52. 52 public class AddToEndSingleByTagStateStrategy implements StateStrategy { public <View extends MvpView> void beforeApply(List currentState, ViewCommand command) { Iterator<ViewCommand<View>> iterator = currentState.iterator(); while (iterator.hasNext()) { ViewCommand<View> entry = iterator.next(); if (entry.getTag().equals(incomingCommand.getTag())) { iterator.remove(); break; } } currentState.add(incomingCommand); } public <View extends MvpView> void afterApply(List currentState, ViewCommand command) { // pass } }
  • 53. Сделать экран деталей конкретной новости 53
  • 54. @InjectViewState public class DetailsPresenter extends MvpPresenter<DetailsView> { public DetailsPresenter(long newsId) { getViewState().showDetails("Details of "" + newsId + """); } } public interface DetailsView extends MvpView { void showDetails(String details); } 54
  • 55. public class DetailsActivity extends MvpAppCompatActivity implements DetailsView { @InjectPresenter DetailsPresenter mDetailsPresenter; @ProvidePresenter DetailsPresenter provideDetailsPresenter() { return new DetailsPresenter(getIntent().getLongExtra("extraDetailsId", 0)); } @Override public void showDetails(String details) { Log.i(DetailsActivity.class.getSimpleName(), details); } } 55
  • 56. 0. Annotation processor: Generate PresenterFields 1. MvpDelegate: onCreate(savedInstanceState) 2. MvpDelegate: Init delegate tag 3. MvpProcessor: Collect all PresenterField for MvpDelegate 4. MvpProcessor: Init each PresenterField 1. MvpProcessor: Generate presenter tag 2. PresenterStore: Get MvpPresenter by type and tag 3. MvpProcessor: MvpPresenter exists? 1. True: 1. MvpProcessor: Init presenter field of Delegated 2. False: 1. PresenterField: Provide presenter 2. PresenterStore: Save presenter 3. MvpProcessor: Init presenter field of Delegated 56
  • 57. 0. Annotation processor: Generate ViewState 1. MvpPresenter: Construct 2. Binder: Bind presenter 3. Binder: Find ViewState for MvpPresenter 4. Binder: Create ViewState 5. Binder: Set ViewState to MvpPresenter 57
  • 58. 1. MvpPresenter: Send command 2. ViewState: Instantiation of ViewCommand 3. ViewState: Get StateStrategy of ViewCommand 4. StateStrategy: Called beforeApply(currentState, incomingCommand) 5. ViewState: Have a Views? 1. False: – 2. True: 1. ViewCommand: Apply to each Views 2. StateStrategy: Called afterApply(currentState, incomingState) 6. ViewState: Attached View 7. ViewState: Apply each ViewCommands 1. ViewCommand: Apply to attached View 2. StateStrategy: Called afterApply(currentState, incomingState) 58
  • 59. 59
  • 60. 1. Нет проблем с жизненным циклом 2. Boilerplate-code генерируется в compile time 3. Можно использовать несколько Presenter в одном месте 4. Можно любой компонент превратить в MvpView Присоединяйтесь к проекту на github.com! PS: https://github.com/senneco/MoxyCases 60
  • 61. 61