Как стать автором
Обновить

Комментарии 52

Предложенный подход не будет работать на практике: подписка Activity на AsyncTask — это наверное самая популярная джуниорская ошибка. Приводит к падениям (или зависаниям, или вообще не понятно к чему — как повезёт) при попытках перевернуть девайс в процессе выполнения сравнительно долгих операций. А чтобы от этой ошибки избавиться, нужно изобразить что-то типа habrahabr.ru/post/240543. И для предложенной красоты места там скорее всего не останется.
Предложенный подход заключается в реализации View классов, а не в использовании AsyncTask. В реальных проектах, конечно, его не нужно использовать для загрузки данных, тем более когда есть множество готовых решений — Robospice, Volley. На счет красоты не согласен, если с умом реализовать модельный слой и не раздувать код контроллера, то все будет ок.
Я тогда наверное не понял о чём статья.
1. Статья называется «Сажаем контроллеры на диету». Т.е. про контроллеры.
2. В начале статьи сказано: «При использовании MVC в Android, Activity или Fragment является контроллером». Т.е. я в первую очередь смотрю на код Activity, потому что сказано, что «статья про контроллеры, а контроллеры — это Activity».

Посмотрел — прокомментировал. Интересно было бы посмотреть, насколько чистый код получился бы, если бы вы канонично связь model->view делали через Loader, а controller->model через IntentService. У меня есть искренние сомнения по поводу того, что от предложенного подхода в итоге что-то останется.
Через Loader'ы загрузку данных с сети тоже не делают)
А для IntentService достаточно сделать хороший уровень абстракции, всю работу с Intent'ами скрыть в отдельной сущности и, если потребуется, написать немного кода в BaseFragment или BaseActivity для автоматического подключения/отключения листенеров
Почему Loader не использовать для сети?
А кто сказал, что Activity является контроллером, а не View, например? Этот класс решает задачи и отображения и обработки событий. Почему вам надо обязательно что-то от него оторвать?
1. Если бы Activity был View тогда где контроллер?
2. Крутые ребята обычно отделяют бизнес-логику от представления
А зачем тащить веб-привычки в мир мобильной разработки?
Я не говорю, что логика должна быть в Activity, но изначально Гуглом сделано так, что этот класс управляет и отображением и обработкой событий. Если логики много, то она перетекает туда, где данные хранятся (модель), а отображение пусть останется тут (в отдельных коротеньких методах).
userView.hideProgressBar();

У вас контроллер практически напрямую управляет отображением, знает о прогресс-баре и видимо вообще обо всех UI-элементах?
Бизнес-логика — это изменение состояния моделей, а у вас контроллер, опять же, меняет отображение. Т.е. в одном месте и бизнес-логика и логика отображения, где разделение?
Суть MVC, как раз таки, в односторонней зависимости, а не в том, что контроллер — место встречи всех.

Отображение знает об интерфейсе контроллере (получение и установка параметров, например, через вызов методов), контроллер знает об интерфейсе модели (тоже самое), модель не знает о них ничего.
Да, контроллер знает о том, что на экране можно показывать и скрывать progress bar, но он не реализует это поведение. Так же контроллер ничего не знает о UI компонентах, он работает только с интерфейсом класса View.
1. Что такое «реализует поведение»? Это то чем занимается ОС, VM или драйвер видеокарты?
2. В чем отличие «userView.showProgressBar();» от «progressBar.setVisibility(View.VISIBLE);»? Дополнительный слой абстракции — это я поняла, но в чем различие вашего Activity от View, если оба управляют отображением? Так ведь можно сколько угодно слоев вводить, причем тут MVC?
1. «Реализует поведение» значит скрыть детали создания и наполнения данными View
2. Отличие в том, что Activity говорит View классу, что нужно сменить состояние экрана или заполнить его данными, а View делает это, причем реализацию метода showProgressBar можно менять для разных View, например на одном экране progress bar нужно показывать в центре экрана, для других это поведение может быть различным
habrahabr.ru/company/redmadrobot/blog/257861/#comment_8416179
В таком случае можно сделать метод более общим, например, showLoading, и реализовывать его по-разному

Вы не можете знать о «будущих» случаях по вашему же примеру, иначе это теряет смысл. И да showLoading — это правильное решение, теперь осталось вас убедить, что контроллер не должен вызывать этот метод у view, а должен иметь такое состояние.
1. «Реализует поведение» значит скрыть детали создания и наполнения данными View

Наверное, «не реализует». Однако, почему «создание и наполнение данными» — это поведение, а отображение/скрытие на экране — что-то другое, не ясно. Казалось бы, наоборот.
2. Отличие в том, что Activity говорит View классу, что нужно сменить состояние экрана или заполнить его данными, а View делает это, причем реализацию метода showProgressBar можно менять для разных View, например на одном экране progress bar нужно показывать в центре экрана, для других это поведение может быть различным

Теперь подумайте, ваша основная задача — отвязать класс контроллера от класса представления, чтобы контроллер можно было использовать с разными представлениями.

При этом вы упорно используете экземпляр view в классе контроллера. Т.е. противоречите себе же.

Класс вашего controller знает об интерфейсе конкретно этого класса view. Знает о его showProgressBar. Если в другом view вообще не будет showProgressBar? Если другое представление вообще никак не реализует отображение загрузки? И у него нет метода showLoading и любого подобного?

Главная моя задача была не отвязать контроллер от представления, а уменьшить количество кода в контроллере, путем создания слоя View классов, с чем они довольно хорошо справляются. Если вы хотите использовать разные View для одного и того же контроллера, логично что у такой View должен быть интерфейс, который она должна реализовать. У другой View не может не быть метода showProgressBar, т.к. он будет в её интерфейсе, либо если сильно хочется не показывать пользователю информацию о процессе загрузки, то реализацию метода можно оставить пустой.
Главная моя задача была не отвязать контроллер от представления, а уменьшить количество кода в контроллере, путем создания слоя View классов, с чем они довольно хорошо справляются.

С чем хорошо справляются, с вынесением части кода в другой класс? Ну да, только почему вы называете это View? Назовите это ControllerPartial, а лучше ActivityPartial, ниже есть пример про region.
Это все нужно городить для того чтобы работать с абстракциями (интерфейсами) и локализовать код, который чаще всего подвергается изменениям(код представления) в отдельном классе

У другой View не может не быть метода showProgressBar, т.к. он будет в её интерфейсе, либо если сильно хочется не показывать пользователю информацию о процессе загрузки, то реализацию метода можно оставить пустой.

Т.е. если мы хотим из этой view убрать отображение загрузки — мы просто должны оставить метод пустым, так?
Теперь представим, что у нас не было этого метода изначально во view. Что мы теперь будем делать? Правильно, менять код контроллера и дописывать туда showProgressBar. И так с каждым изменением отображения…
Само собой, если мы хотим убрать из View отображение progress bar'a, или установку данных с помощью showUser, то это коснется контроллера, но это будет изменение одной строчки. Если же мы захотим поменять способ отображения, то это коснется только View
Если же мы захотим поменять способ отображения, то это коснется только View

Это просто вынесение части логики в другое место. Вы можете точно так же создать класс ProgressBarController и в Activity вызывать ProgressBarController.show(). Тогда при изменении способа отображения прогресс-бара — activity-класс не будет меняться.
Этот паттерн называется — декомпозиция, а не MVC.
Тогда MVC можно назвать декомпозицей кода на модельные классы, классы представления и контроллеры. О чем и речь в статье
Тогда MVC можно назвать декомпозицей кода на модельные классы, классы представления и контроллеры. О чем и речь в статье

MVC — можно назвать декомпозицией, а то, о чем речь в статье — нет.
Ну как же, рассказывается о контроллере, о View, тут и MVC рядом.
Ну если контроллер и view — это любые классы, без классификации их смысла, просто содержащие в названии (или в мыслях) «controller» и «view», то хорошо, вы описали MVC.
Ок. Давайте введем некоторые термины, т.к. мы по-разному понимаем MVC

Контроллер — ловит события от пользователя (клики, свайпы и тд) и обрабатывает их, ничего не знает о том как отображать данные
View — содержит информацию как визуализировать данные, не содержит никакой логики обработки событий
Model — предоставляет данные

Что и представлено в статье. Вы хотели создать ProgressBarController, но я не могу его назвать контроллером, т.к. там нет взаимодействия с пользователем. Так же не могу создать ControllerPartial или ActivityPartial по той же причине. А вот View отличное название, т.к. все что делает этот класс это визуализирует данные и под описание контроллера никак не подходит.
Контроллер — ловит события от пользователя (клики, свайпы и тд) и обрабатывает их, ничего не знает о том как отображать данные

У вас контроллер прекрасно знает, что состояние loading — означает показать progressbar. Это именно как. Т.е., ваш контроллер знает из чего состоит View (в ней есть прогрессбар), а значит ваша MVC не несет никакой практической ценности, ведь отделения логики от представления нет. В одном месте хранятся знания о модели и о представлении. А так как единственная и самая главная ценность MVC именно в этом, то ваша архитектура — не MVC.

Вы хотели создать ProgressBarController, но я не могу его назвать контроллером, т.к. там нет взаимодействия с пользователем.

Ок, пусть будет TextBoxController с подпиской на onchange событие.
или ActivityPartial по той же причине

?
А вот View отличное название, т.к. все что делает этот класс это визуализирует данные и под описание контроллера никак не подходит.

View — отличное название, с этим ведь никто и не спорит, только внимание в 3 раз задаю вопрос. В чем смысл этого разделения? Я привела кучу примеров и везде требовалось изменить код вашего контроллера и view.

Вы написали, что смысл просто в вынесении части кода, но причем тут MVC?
Вы считаете что MVC — это обязательно MVC с активной моделью, в которой контроллер не связан с View? В статье показан MVC с пассивной моделью когда контроллер обращается к View для его перерисовки.
Вы считаете что MVC — это обязательно MVC с активной моделью, в которой контроллер не связан с View?

M — модель, предметная область, бизнес-логика.
C — Промежуточное звено для уменьшения связаности.
V — Интерфейс для конечного клиента.
Собственно, весь смысл MVC (в отличии от других шаблонов) именно в контроллере и именно в уменьшении связанности.
Нет никаких правил, что именно должно быть в модели, контроллере и виде, правило одно — в этом должен быть практический смысл. А главный смысл — повторное использование и минимальные изменения частей кода при изменении тех. задания.

В статье показан MVC с пассивной моделью когда контроллер обращается к View для его перерисовки.

В статье показан пример, в котором при изменении модели нам придется менять и модель и контроллер. При изменении отображения, нам придется менять и отображение и контроллер.
Т.е. контроллер является ТТУКом, который вместо внедрения еще одного слоя для уменьшения связанности — увеличивает ее. В одном месте находится и бизнес-логика (изменение модели), и работа с интерфейсом (обработка событий), и отображение (showProgressBar).
Т.е. никакого разделения на MVC нет, все в одном классе. Зато есть вынесение части логики отображения в другой класс.

И да, пассивная модель — это когда мы модель(бизнес-логику) описываем в одном классе с контролером. Это уже тоже MVC с натяжкой, но все еще лучше, чем у вас — все три части в одном месте.

Вопрос: как вы предлагаете реализовывать контроллер, ничего не знающий о вью? Кто тогда должен решать, когда отобразить прогресс?

Тысячу раз уже обсуждали, что MVC и андроид не совместимы. Зачем гордить все это, если SDK нам предоставляет готовые компоненты приложения, которые по своей натуре малосвязны? Эта статья нормально смотрелась в 2009-2010 году, когда народ перешел из web программирования и тянул свои концепции, но сейчас-то уже обо всем догорились и пора перестать заниматься вот этим.
Сейчас работаю на улучшением архитектуры своих приложений. Не подскажете, что тогда юзать тру, если не MVC?
Следующая статья будет по MVP. Но правильное использование MVC это уже лучше чем ничего
Я все же прочитал статью и код ), и могу сказать, что согласен с вашим подходом. Только к MVC он отношения не имеет.
И на этом спасибо)
Используйте сервисы, контент провайдеры, бродкаст ресиверы и активити.
Не знал, что Кэп пишет под Android) Это понятно, но как это все красиво архитектурно оформить, вот в чем вопрос. Если не MVC.
Это и есть архитектура. Все это слабосвязные компноенты by design. MVC, как уже в 1000 раз выяснили в комментариях, в условиях Android SDKне возможен. Вот наглядный пример.
И чего сразу минусовать? Я ведь согласен, что mvc на дроиде реализовывать — это оверинжиниринг. Но «как не делать mvc правильно» тоже надо уметь. И ioschedule не лучший пример, по крайней мере, за 2014 год. Подождем 2015-го, вроде не за горами.
Почему не лучший пример? Инженеры из команды Android показывают, как они пишут приложения — что может быть лучше?

Минус скорей всего поставили за «Кэп пишет под Android».
Согласен, посмотрел на код и он явно плохой. Хотя в целом, «архитектура» похожа на ту, что обычно все используют.
Легок на помине) Только что приложение обновилось до 2015. Ждем код. Или он уже есть, надо посмотреть.
Ан нет, как обычно, после ивента.
Это кстати наглядный пример убогости разработки под андроид, приложение имеет баги с восстановлением состояния и имеет столько кода внутри (под 100тыс строк xml+java), что страшно становится, а написано гуглом.
Это все нужно городить для того чтобы работать с абстракциями (интерфейсами) и локализовать код, который чаще всего подвергается изменениям(код представления) в отдельном классе
Теперь представьте, что вместо прогресс-бара мы хотим крутить spinner или просто писать слово загрузка. В вашем примере придется менять код контроллера и код представления.
В таком случае можно сделать метод более общим, например, showLoading, и реализовывать его по-разному
У вас есть статистика какой код чаще меняется? Посмотрите исходники гугловых приложений — там нет никакого MVC.
UPD: я вижу вы какие-то стажировки проводите. Пожалуйста, не учите этому там!
Идея хорошая, но на практике часто связь между активити и контролами слишком большая чтоб их разделять.
Я в таких случаях группирую код относящийся к разным частям с помощью регионов (//region в Android Studio).
Также отсутствие в Java ивентов и делегатов усложняет реализацию красивых интерфейсов.
Дополню пост этой древней статьей.
Есть мнение, что MVC в андроиде уже есть: View — это xml-разметка, Controller — это активити, ну а Model остаётся вам на реализацию.
Хочу также добавить что в Android разработке чаще используется разновидность MVC-паттерна — MVP (Model-View-Presenter).
Более подробно можно почитать о них например тут:
http://habrahabr.ru/post/215605/
http://antonioleiva.com/mvp-android/ (на английском)
http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/ (на английском)
Используя androidannotations @ViewGroup/View можно вынести по крайней мере часть UI логики из активити в другой класс, но целиком избавится от UI кода в активити не получится, но по крайней можно сократить и упростить за счет аннотаций. Теперь может где-то пригодится и биндинг, но вполне может оказаться, что проще и понятнее написать геттер/сеттер во вью, чем пытаться потребить биндинг от гугла :)

Добиться какой-то более-менее похожей реализации MVC вряд ли получится из-за специфического апи андроида, когда все прибито к активити гвоздями и завязано на ее жизненный цикл.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.