Паттерн MVС появился достаточно давно и создавался с целью разделения бизнес-логики приложения от представления. Но далеко не все программисты реализуют его правильно, из-за чего возникают «Толстые тупые уродливые контроллеры» содержащие тонны кода. В этой статье пойдет речь о правильной реализации View классов, для того чтобы уменьшить количество кода в контроллерах и оставить место чистой бизнес-логике приложения.



Все, наверное, должны знать что MVC бывает двух типов — с активной моделью и пассивной, различие которых кроется в том, что пассивная модель служит простым источником данных (как, например, DAO для базы данных), а активная модель сама обновляет состояние своих подписчиков — View. Пассивная модель является более универсальной и простой, кроме того чаще всего используется в разработке, поэтому она будет использоваться для примера в этой статье. Давайте взглянем на её схему.

Пользователь взаимодействует с контроллером, контроллер запрашивает данные у модели и заполняет View, который отображается пользователю, всё просто.

  • При использовании MVC в Android, Activity или Fragment является контроллером.
  • Модель — набор классов, которые служат источником данных приложения.
  • View — xml разметка и кастомные View компоненты, на подобие Button и т. д.

Если с контроллером и моделью, вроде бы, всё понятно, то со View возникают некоторые трудности, главная их причина — View, как такого, нет, никто не задумывается о создании отдельных View классов с интерфейсом, через который контроллер мог бы передавать данные для отображения. Большинство просто создаёт xml разметку и заполняет её прямо в контроллере, из-за чего код, который по идее должен содержать бизнес-логику переполняется деталями отображения, такими как цвет текста, размер шрифта, установка текста в TextView, работа с ActionBar'ом, NavigatonDrawer'ом и прочими. В результате код Activity разрастается до 1000 строк и на первый взгляд содержит какой-то мусор.

Давайте взглянем на то, как делается типичное Android приложение без создания отдельных View классов, и на другое, в котором в полной мере используется View.

Наше приложение будет решать вполне распространенную задачу — загружать и отображать профайл пользователя. Начнем реализацию.

Для этого создадим модельный класс User, в котором будет храниться имя и фамилия пользователя.

public class User {

    private final String firstname;
    private final String lastname;

    public User(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }

    // getters
}

И класс provider, который будет её «загружать». Этот класс создан для демонстрационных целей, в реальном проекте не следует использовать AsyncTask для загрузки данных и не стоит писать свой велосипед, который даже не учитывает жизненный цикл Activity и не обрабатывает ошибки, лучше использовать готовое решение, например, RoboSpice. Здесь этот класс нужен, по большей части, только для того, чтобы скрыть детали реализации загрузки данных в отдельном потоке.

public class UserProvider {

    // результат вернем в Callback
    public void loadUser(Callback callback) {
        new LoadUserTask(callback).execute();
    }

    public class LoadUserTask extends AsyncTask<Void, Void, User> {
        private Callback callback;

        public LoadUserTask(Callback callback) {
            this.callback = callback;
        }

        @Override
        protected User doInBackground(Void... params) {
            User user = new User("firstname", "lastname");
            return user;
        }

        @Override
        protected void onPostExecute(User user) {
            super.onPostExecute(user);
            callback.onUserLoaded(user);
        }
    }

    public interface Callback {
        void onUserLoaded(User user);
    }
}

Далее создается xml верстка, которую мы опустим и контроллер, который должен связать View и Model, и внести немного бизнес-логики в наше приложение. В виде контроллера выступает Activity, обычно он реализуется примерно так:

public class UserProfileActivity extends Activity implements Callback {

    private TextView firstnameTxt, lastnameTxt;
    private ProgressBar progressBar;
    private UserProvider userProvider;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_profile);

        firstnameTxt = (TextView) findViewById(R.id.firstname);
        lastnameTxt = (TextView) findViewById(R.id.lastname);
        progressBar = (Progressbar) findViewById(R.id.progressBar);

        userProvider = new UserProvider();
        loadUser();
    }

    @Override
    public void onUserLoaded(User user) {
        hideProgressBar();
        showUser(user);
    }
    
    private void loadUser() {
        showProgressBar();
        userProvider.loadUser(this);
    }

    public void showUser(User user) {
        firstnameTxt.setText(user.getFirstname());
        lastnameTxt.setText(user.getLastname());
    }

    public void showProgressBar() {
        progressBar.setVisibility(View.VISIBLE);
    }

    public void hideProgressBar() {
        progressBar.setVisibility(View.INVISIBLE);
    }
}

При открытии экрана начинается загрузка профайла, отображается progress bar, когда профайл будет загружен, progress bar скрывается и происходит наполнение экрана данными.
Как видно из этого кода — в нём перемешивается работа с представлением и бизнес-логика.
Если сейчас все выглядит не так плохо, то при развитии проекта такой код станет плохочитаемым и трудноподдерживаемым.

Давайте вспомним про ООП и добавим немного абстракции в наш код.

public class UserView {

    private final TextView firstnameTxt, lastnameTxt;
    private final ProgressBar progressBar;

    public UserView(View rootView) {
        firstnameTxt = (TextView) rootView.findViewById(R.id.firstname);
        lastnameTxt = (TextView) rootView.findViewById(R.id.lastname);
        progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar);
    }

    public void showUser(User user) {
        firstnameTxt.setText(user.getFirstname());
        lastnameTxt.setText(user.getLastname());
    }

    public void showProgressBar() {
        progressBar.setVisibility(View.VISIBLE);
    }

    public void hideProgressBar() {
        progressBar.setVisibility(View.INVISIBLE);
    }
}

View берет на себя всю работу с представлением Activity. Для отображения профайла пользователя нужно просто воспользоваться методом showUser(User) и передать ему модельный объект. В реальном проекте для View желательно создать базовый класс, в который можно перенести вспомогательные методы, такие как showProgressBar(), hideProgressBar(), и другие. В результате вся логика работы с представлением вынесена из Activity в отдельную сущность, что в разы уменьшает объемы кода контроллера и создаёт прозрачную абстракцию работы с View.

Activity же теперь ничего не знает о TextView и других контролах. Все взаимодействие с представлением происходит с помощью класса UserView и его интерфейса.

public class UserProfileActivity extends Activity {

    private UserView userView;
    private UserProvider userProvider;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);

        userView = new UserView(getWindow().getDecorView())
        userProvider = new UserProvider();

        loadUser();
    }

    @Override
    public void onUserLoaded(User user) {
        userView.hideProgressBar();
        userView.showUser(user);
    }

    private void loadUser() {
        userView.showProgressBar();
        userProvider.loadUser(this);
    }
}

Теперь контроллер оперирует всего двумя сущностями — UserView и UserProvider, в нём нет тонкостей реализации отображения данных. Код стал чище и понятней.

Сейчас класс UserView просто отображает данные, возможно вы захотите сделать сохранение состояния между поворотами экранов — этот вопрос можно легко решить создав метод, записывающий состояние View в Parcelable или Bundle. Также, скорей всего, понадобится возможность обработки нажатий, в этом случае сам OnClickListener лучше создать во View классе и в него передать Callback, который реализует ваш контроллер.

Вот, собственно, и все. Так решается проблема недооценённых View в Android. При использовании этого подхода количество кода в ваших контроллерах заметно уменьшится, уровень абстракций возрастет и доллар опять будет стоить 30 рублей.

Читайте также:
Стилизация iOS-приложений: как мы натягиваем шрифты, цвета и изображения
Архитектурный дизайн мобильных приложений
Архитектурный дизайн мобильных приложений: часть 2

Комментарии (51)


  1. js605451
    13.05.2015 18:35

    Предложенный подход не будет работать на практике: подписка Activity на AsyncTask — это наверное самая популярная джуниорская ошибка. Приводит к падениям (или зависаниям, или вообще не понятно к чему — как повезёт) при попытках перевернуть девайс в процессе выполнения сравнительно долгих операций. А чтобы от этой ошибки избавиться, нужно изобразить что-то типа habrahabr.ru/post/240543. И для предложенной красоты места там скорее всего не останется.


    1. anton9088 Автор
      13.05.2015 18:46
      +2

      Предложенный подход заключается в реализации View классов, а не в использовании AsyncTask. В реальных проектах, конечно, его не нужно использовать для загрузки данных, тем более когда есть множество готовых решений — Robospice, Volley. На счет красоты не согласен, если с умом реализовать модельный слой и не раздувать код контроллера, то все будет ок.


      1. js605451
        13.05.2015 20:00

        Я тогда наверное не понял о чём статья.
        1. Статья называется «Сажаем контроллеры на диету». Т.е. про контроллеры.
        2. В начале статьи сказано: «При использовании MVC в Android, Activity или Fragment является контроллером». Т.е. я в первую очередь смотрю на код Activity, потому что сказано, что «статья про контроллеры, а контроллеры — это Activity».

        Посмотрел — прокомментировал. Интересно было бы посмотреть, насколько чистый код получился бы, если бы вы канонично связь model->view делали через Loader, а controller->model через IntentService. У меня есть искренние сомнения по поводу того, что от предложенного подхода в итоге что-то останется.


        1. anton9088 Автор
          13.05.2015 20:04
          +1

          Через Loader'ы загрузку данных с сети тоже не делают)
          А для IntentService достаточно сделать хороший уровень абстракции, всю работу с Intent'ами скрыть в отдельной сущности и, если потребуется, написать немного кода в BaseFragment или BaseActivity для автоматического подключения/отключения листенеров


          1. vladlichonos
            14.05.2015 03:38

            Почему Loader не использовать для сети?


    1. jaleel
      13.05.2015 18:49

      upd. ответили


  1. Revertis
    13.05.2015 19:03
    +1

    А кто сказал, что Activity является контроллером, а не View, например? Этот класс решает задачи и отображения и обработки событий. Почему вам надо обязательно что-то от него оторвать?


    1. anton9088 Автор
      13.05.2015 19:07
      +1

      1. Если бы Activity был View тогда где контроллер?
      2. Крутые ребята обычно отделяют бизнес-логику от представления


      1. Revertis
        13.05.2015 19:17
        +1

        А зачем тащить веб-привычки в мир мобильной разработки?
        Я не говорю, что логика должна быть в Activity, но изначально Гуглом сделано так, что этот класс управляет и отображением и обработкой событий. Если логики много, то она перетекает туда, где данные хранятся (модель), а отображение пусть останется тут (в отдельных коротеньких методах).


      1. sferrka
        13.05.2015 19:50
        +2

        userView.hideProgressBar();

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

        Отображение знает об интерфейсе контроллере (получение и установка параметров, например, через вызов методов), контроллер знает об интерфейсе модели (тоже самое), модель не знает о них ничего.


        1. anton9088 Автор
          13.05.2015 19:57
          +1

          Да, контроллер знает о том, что на экране можно показывать и скрывать progress bar, но он не реализует это поведение. Так же контроллер ничего не знает о UI компонентах, он работает только с интерфейсом класса View.


          1. sferrka
            13.05.2015 20:12
            +2

            1. Что такое «реализует поведение»? Это то чем занимается ОС, VM или драйвер видеокарты?
            2. В чем отличие «userView.showProgressBar();» от «progressBar.setVisibility(View.VISIBLE);»? Дополнительный слой абстракции — это я поняла, но в чем различие вашего Activity от View, если оба управляют отображением? Так ведь можно сколько угодно слоев вводить, причем тут MVC?


            1. anton9088 Автор
              13.05.2015 20:19
              +1

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


              1. sferrka
                13.05.2015 20:35
                +1

                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 и любого подобного?


                1. anton9088 Автор
                  13.05.2015 20:48
                  +1

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


                  1. sferrka
                    13.05.2015 20:53
                    +1

                    Главная моя задача была не отвязать контроллер от представления, а уменьшить количество кода в контроллере, путем создания слоя View классов, с чем они довольно хорошо справляются.

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

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

                    Т.е. если мы хотим из этой view убрать отображение загрузки — мы просто должны оставить метод пустым, так?
                    Теперь представим, что у нас не было этого метода изначально во view. Что мы теперь будем делать? Правильно, менять код контроллера и дописывать туда showProgressBar. И так с каждым изменением отображения…


                    1. anton9088 Автор
                      13.05.2015 20:59

                      Само собой, если мы хотим убрать из View отображение progress bar'a, или установку данных с помощью showUser, то это коснется контроллера, но это будет изменение одной строчки. Если же мы захотим поменять способ отображения, то это коснется только View


                      1. sferrka
                        13.05.2015 21:11

                        Если же мы захотим поменять способ отображения, то это коснется только View

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


                        1. anton9088 Автор
                          13.05.2015 21:15

                          Тогда MVC можно назвать декомпозицей кода на модельные классы, классы представления и контроллеры. О чем и речь в статье


                          1. sferrka
                            13.05.2015 21:19
                            -1

                            Тогда MVC можно назвать декомпозицей кода на модельные классы, классы представления и контроллеры. О чем и речь в статье

                            MVC — можно назвать декомпозицией, а то, о чем речь в статье — нет.


                            1. anton9088 Автор
                              13.05.2015 21:44
                              -2

                              Ну как же, рассказывается о контроллере, о View, тут и MVC рядом.


                              1. sferrka
                                13.05.2015 22:07

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


                                1. anton9088 Автор
                                  14.05.2015 00:03
                                  +2

                                  Ок. Давайте введем некоторые термины, т.к. мы по-разному понимаем MVC

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

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


                                  1. sferrka
                                    14.05.2015 09:18
                                    +1

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

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

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

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

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

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

                                    Вы написали, что смысл просто в вынесении части кода, но причем тут MVC?


                                    1. anton9088 Автор
                                      14.05.2015 13:22

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


                                      1. sferrka
                                        14.05.2015 14:01

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

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

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

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

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


  1. Divers
    13.05.2015 19:26

    Тысячу раз уже обсуждали, что MVC и андроид не совместимы. Зачем гордить все это, если SDK нам предоставляет готовые компоненты приложения, которые по своей натуре малосвязны? Эта статья нормально смотрелась в 2009-2010 году, когда народ перешел из web программирования и тянул свои концепции, но сейчас-то уже обо всем догорились и пора перестать заниматься вот этим.


    1. Bringoff
      13.05.2015 19:38

      Сейчас работаю на улучшением архитектуры своих приложений. Не подскажете, что тогда юзать тру, если не MVC?


      1. anton9088 Автор
        13.05.2015 20:00
        +1

        Следующая статья будет по MVP. Но правильное использование MVC это уже лучше чем ничего


        1. Divers
          13.05.2015 20:59
          +2

          Я все же прочитал статью и код ), и могу сказать, что согласен с вашим подходом. Только к MVC он отношения не имеет.


          1. anton9088 Автор
            13.05.2015 21:01

            И на этом спасибо)


      1. Divers
        13.05.2015 20:27
        -1

        Используйте сервисы, контент провайдеры, бродкаст ресиверы и активити.


        1. Bringoff
          14.05.2015 10:29
          -1

          Не знал, что Кэп пишет под Android) Это понятно, но как это все красиво архитектурно оформить, вот в чем вопрос. Если не MVC.


          1. Divers
            14.05.2015 11:16
            -1

            Это и есть архитектура. Все это слабосвязные компноенты by design. MVC, как уже в 1000 раз выяснили в комментариях, в условиях Android SDKне возможен. Вот наглядный пример.


            1. Bringoff
              14.05.2015 12:50

              И чего сразу минусовать? Я ведь согласен, что mvc на дроиде реализовывать — это оверинжиниринг. Но «как не делать mvc правильно» тоже надо уметь. И ioschedule не лучший пример, по крайней мере, за 2014 год. Подождем 2015-го, вроде не за горами.


              1. Divers
                14.05.2015 13:14

                Почему не лучший пример? Инженеры из команды Android показывают, как они пишут приложения — что может быть лучше?

                Минус скорей всего поставили за «Кэп пишет под Android».


                1. Bringoff
                  14.05.2015 13:23

                  Была когда-то статья по этому поводу: habrahabr.ru/post/241139


                  1. Divers
                    14.05.2015 13:37

                    Согласен, посмотрел на код и он явно плохой. Хотя в целом, «архитектура» похожа на ту, что обычно все используют.


                    1. Bringoff
                      14.05.2015 16:01

                      Легок на помине) Только что приложение обновилось до 2015. Ждем код. Или он уже есть, надо посмотреть.


                      1. Bringoff
                        14.05.2015 16:42

                        Ан нет, как обычно, после ивента.


            1. kemsky
              08.06.2015 18:17

              Это кстати наглядный пример убогости разработки под андроид, приложение имеет баги с восстановлением состояния и имеет столько кода внутри (под 100тыс строк xml+java), что страшно становится, а написано гуглом.


    1. anton9088 Автор
      13.05.2015 20:09
      +1

      Это все нужно городить для того чтобы работать с абстракциями (интерфейсами) и локализовать код, который чаще всего подвергается изменениям(код представления) в отдельном классе


      1. sferrka
        13.05.2015 20:18

        Теперь представьте, что вместо прогресс-бара мы хотим крутить spinner или просто писать слово загрузка. В вашем примере придется менять код контроллера и код представления.


        1. anton9088 Автор
          13.05.2015 20:22
          +1

          В таком случае можно сделать метод более общим, например, showLoading, и реализовывать его по-разному


      1. Divers
        13.05.2015 20:24
        +1

        У вас есть статистика какой код чаще меняется? Посмотрите исходники гугловых приложений — там нет никакого MVC.


  1. Divers
    13.05.2015 19:30
    -3

    UPD: я вижу вы какие-то стажировки проводите. Пожалуйста, не учите этому там!


  1. r_ii
    13.05.2015 20:33
    +1

    Идея хорошая, но на практике часто связь между активити и контролами слишком большая чтоб их разделять.
    Я в таких случаях группирую код относящийся к разным частям с помощью регионов (//region в Android Studio).
    Также отсутствие в Java ивентов и делегатов усложняет реализацию красивых интерфейсов.
    Дополню пост этой древней статьей.


  1. forceLain
    14.05.2015 11:56
    +3

    Есть мнение, что MVC в андроиде уже есть: View — это xml-разметка, Controller — это активити, ну а Model остаётся вам на реализацию.


  1. bejibx
    18.05.2015 14:47

    Хочу также добавить что в 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/ (на английском)


  1. anton9088 Автор
    07.06.2015 18:38

    Гугл наконец-то занялся архитектурой сам и сделал MVVM)
    developer.android.com/tools/data-binding/guide.html


  1. kemsky
    08.06.2015 18:11

    Используя androidannotations @ViewGroup/View можно вынести по крайней мере часть UI логики из активити в другой класс, но целиком избавится от UI кода в активити не получится, но по крайней можно сократить и упростить за счет аннотаций. Теперь может где-то пригодится и биндинг, но вполне может оказаться, что проще и понятнее написать геттер/сеттер во вью, чем пытаться потребить биндинг от гугла :)

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