MVC для андроид

в 14:44, , рубрики: android, annotations, mvc, patterns, patterns and practices, Разработка под android, метки: , , , ,

Я считаю, что работа программиста заключается не в том, чтобы писать код а в том, чтобы оптимизировать процессы. Мы пишем код, что бы его пользователь мог быстрее и эффективнее достичь мирового господства, например. И было бы немного странно оптимизировать работу других и не оптимизировать свою. Сапожник без сапог — это нерационально.

Итак. Стал я недавно писать вторую версию своей апп для таких же религиозных фанатиков как и я. Апп не важна, важно, что двухстороннее связывание виджетов с данными — довольно рутинная, чреватая копипейстом работа. Особенно весело становится, если есть зависимости: Если изменился этот текст — обнови тот. Уже на втором экране, будучи вдохновлённым Butter Knife проектом я понял, что здесь огромный простор для генерализации (и, как ни странно, ничего подобного не нашёл).

Встречайте, проект Bandera*

(код примера копирую у себя же)

  • Указываем bandera-compile.jar как процессор компиляционных аннотаций
  • Описываем класс модели:
    public class MainActivityModel {
        private int catCount;
    
        public MainActivityModel(CatRecordFromDb cats) {
          // init your viewmodel here 
          // ...
        }
    
        @BindModel({ R.id.practice_image, R.id.buttonStart }) // RO binding to imageUri for ImgView and ImgButton
        public String getFancyImage() {
          return getModel().imageUrl;
        }
    
        @BindModel(R.id.editNumberOfCats) // getter for EditText value initialisation
        public int getCatsCount() {       // method name can be anything, getters just need the "get" in front
          return catCount;                // conversion from int to String happens magically at google offices* (even offline!)
        }
    
        @BindModel(R.id.editNumberOfCats)         // setter to update the model from the control
        public void setCatNumber(int catCount) {  // setter name doesn't need to match getter's, just be "set<Whatever>"
          this.catCount = catCount;               // the value is already converted into target type
          recalculateTotal();                     // do the magic after cat count changed
        }
    }    // * Measurement of correctness of this description is pending indifinitely
    

  • В активити связываем модель и представление:
    binder = doo.bandera.Models.Bind(this, new MainActivityModel(catsFromDb)); // doo.bandera.Models.Bind for your activity/model pair is generated during compilation
    

  • Ну и если что-то изменилось вне связки, сообщаем об этом:
    binder.updateDirtyValues(); // scans what changed in the model and updates widgets
    

  • Указываем bandera-runtime.jar как включаемую в апк зависимость.
  • Всё работает™

То есть рутина ушла в библиотеку. Логика вынесена в ViewModel (я знаю, это не совсем MVC а скорей MV-C). Все счастливы.

Проект пишется прагматично под свои нужды, поэтому поддерживаются пока только TextView, EditText, DateTimePicker, ProgressBar, ImageView, ImageButton (картинка). Для событий я использую всё тот же Butter Knife.

Ну и особая прелесть в том, что связывающий код генерируется при компиляции**, то есть традиционных андроид страхов annotations-runtime-reflection-slow-as-hell просто нет.

* Слово созвучное Binding и Android
** Я совсем не доволен, как именно я этот код генерирую, но пока Всё работает™ и Красиво мы сделаем потом™

Автор: dooreelkow

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js