Создание Android приложения с использованием Anko Layouts и Anko Coroutines

image


Примерно год назад я начал использовать Kotlin в своих Android проектах. Мне хотелось попробовать что-то новое, что было бы интересно изучать. Тогда я и наткнулся на Anko. К тому времени писать UI на xml порядком осточертело. Мне всегда нравилось писать интерфейс руками, не прибегая к WYSIWYG и xml-разметке, используемой в Android Studio. Единственный минус заключается в том, что для проверки любого изменения придется перезапускать приложение. Можно использовать плагин, который показывает как будет выглядеть ui не запуская приложения, но мне он показался довольно странным. Так же у него есть крутая возможность конвертирования xml в Anko Layouts DSL.


Самый большой недостаток библиотеки — практически полное отсутствие документации. Чтобы разобраться, как ее правильно использовать, приходилось часто заглядывать в исходники. В этой статье будет подробно разобрано создание приложения используя Anko Layouts и Anko Coroutines.


Сама библиотека Anko разделяется на 4 независимые части:


  • Anko Layouts — построение UI.
  • Anko Commons — полезные инструменты и функции.
  • Anko SQLite — работа с базой данных SQLite.
  • Anko Coroutines — полезные инструменты для работы с корутинами.

Для добавления библиотеки в проект достаточно добавить одну строчку в зависимости проекта:


implementation "org.jetbrains.anko:anko:$anko_version"


где anko_version — текущая версия библиотеки, прописанная в build.gradle файле на project уровне:


ext.anko_version='0.10.8'


Anko Layouts


Anko Layouts позволяет разрабатывать UI Android приложения более эффективно, чем это было с использованием Java.


Основным игроком на поле у нас является интерфейс AnkoComponent<T> с единственным методом createView, принимающим AnkoContext<T> и возвращающим View. Как раз в этом методе и происходит создание всего UI. Интерфейс AnkoContext<T> является оберткой над ViewManager. Подробнее о нем будет позже.


Немного разобравшись с тем, как устроен AnkoComponent<T>, попробуем создать простенький UI в классе нашей Activity. Стоит уточнить, что вот такое "прямое" написание UI возможно только в Activity, так как для нее написана отдельная extension функция ankoView, в которой вызывается метод addView, и уже в самом методе создается AnkoContextImpl<T> с параметром setContentView = true.


class AppActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        verticalLayout {
            lparams(matchParent, matchParent)
            gravity = Gravity.CENTER
            textView("Cool Anko TextView") {
                gravity = Gravity.CENTER
            }
        }
}

Очевидно, что для чего-то большего, чем один TextView, метод onCreate быстро превратится в подобие свалки. Попробуем отделить класс Activity от UI. Для этого создадим еще один класс, в котором он будет описываться.


class AppActivityUi: AnkoComponent<AppActivity> {
    override fun createView(ui: AnkoContext<AppActivity>): View = with(ui) {
        verticalLayout {
            lparams(matchParent, matchParent)
            gravity = Gravity.CENTER
            textView("Cool Anko TextView") {
                gravity = Gravity.CENTER
            }
        }
    }
}

Теперь, для того, что бы передать нашей Activity наш UI, можно использовать


AppActivityUi().setContentView(this)

Хорошо, но как быть, если мы хотим создать UI для фрагмента? Для этого можно использовать метод createView напрямую, вызывая его из onCreateView метода фрагмента. Выглядит это следующим образом:


class AppFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        return AppFragmentUi().createView(AnkoContext.create(requireContext(), this))
    }
}

Как уже было сказано — AnkoContext<T> является оберткой над ViewManager. У его вспомогательного объекта (companion object) есть три основных метода, возвращающих AnkoContext<T>. Разберем их поподробнее.


create


 fun <T> create(ctx: Context, owner: T, setContentView: Boolean = false): AnkoContext<T>

и его брат-близнец


fun create(ctx: Context, setContentView: Boolean = false): AnkoContext<Context>

возвращают AnkoContextImpl<T>.


Методы используются во всех стандартных случаях, как, например, в предыдущих примерах с Activity и Fragment. Самым интересным здесь являются параметры owner и setContentView. Первый позволяет передать в метод createView instance конкретного Fragment'a, Activity или чего-либо еще.


MyComponent().createView(AnkoContext.create(context, myVew))

class MyComponent: AnkoComponent<View> {
    override fun createView(ui: AnkoContext<View>): View = with(ui) {
        val myView: View= ui.owner
        // И дальше по инструкции
    }
}

Второй параметр — setContentView — автоматически попробует добавить полученный view, если Context является экземпляром Activity или ContextWrapper. Если у него это не получится — он выкинет IllegalStateException.


createDelegate


Этот метод может быть очень полезен, однако в официальной документации на гихабе о нем нигде не написано. Наткнулся я на него в исходниках, когда решал проблему раздутия UI классов:


fun <T: ViewGroup> createDelegate(owner: T): AnkoContext<T> = DelegatingAnkoContext(owner)

Он позволяет добавить результат createView компонента в owner.


Рассмотрим его использование на примере. Допустим, у нас есть большой класс, описывающий один из экранов приложения — AppFragmentUi.


verticalLayout {
    relativeLayout {
        id = R.id.toolbar
        // тут много вложенных view
    }
    relativeLayout{
        id = R.id.content
        // тут тоже много вложенных view
    }
}

Логически его можно разделить на две части — на тулбар и контент, AppFragmentUiToolbar и AppFragmentUiContent соответственно. Тогда наш основной класс AppFragmentUi станет гораздо проще:


class AppFragmentUi: AnkoComponent<AppFragment> {

    override fun createView(ui: AnkoContext<AppFragment>) = with(ui) {
        verticalLayout {
            AppFragmentUiToolbar().createView(AnkoContext.createDelegate(this))
            AppFragmentUiContent().createView(AnkoContext.createDelegate(this))
        }
    }
}

class AppFragmentUiToolbar : AnkoComponent<_LinearLayout> {
    override fun createView(ui: AnkoContext<_LinearLayout>): View = with(ui.owner) {
        relativeLayout {
            id = R.id.toolbar
            // тут вложенные view
        }
    }
}

Обратите внимание, что в функцию with в качестве объекта передается не ui, a ui.owner.
Таким образом у нас выполняется следующий алгоритм:


  1. Создается инстанс компонента.
  2. Метод createView создает View который будет добавлен.
  3. Полученный View добавляется в owner.

Более приближенный аналог: this.addView(AppFragmentUiToolbar().createView(...))
Как можно заметить, вариант с createDelegate более приятен для чтения.


createReusable


Похоже на стандартный AnkoContext.create, но с небольшим дополнением — корневым view считается самый последний:


class MyComponent: AnkoComponent<MyObject> {
    override fun createView(ui: AnkoContext<MyObject>): View = with(ui) {
        textView("Some text")
        // в этом моменте не будет выкинут IllegalStateException: View is already set 
        // На экране будет показан "Another text"
        textView("Another text") 
    }
}

В стандартной реализации, если корневой view установлен — попытка установить второй view параллельно вызовет exception.


Метод createReusable возвращает класс ReusableAnkoContext, который наследуется от AnkoContextImpl и переопределяет метод alreadyHasView().


CustomView


К счастью, Anko Layouts не ограничивается лишь этим функционалом. Если нам нужно показать собственный CustomView, нам не придется писать


verticalLayout {
    val view = CustomView(context)
    //....
    addView(view) // или addView(view.apply { ... })
}

Для этого можно добавлять свою обертку, которая будет делать тоже самое.


Основным компонентов здесь выступает extension метод <T: View>ankoView(factory: (Context) -> T, theme: Int, init: T.() -> Unit) от ViewManager, Context или Activity.


  • factory — функция, на вход которой передаётся Context и возвращается View. По сути является фабрикой, в которой происходит создание View.
  • theme — ресурс стиля, который будет применен для текущей view.
  • init — функция, в которой для созданной View будут устанавливаться необходимые параметры.

Добавим свою реализацию для нашего CustomView


inline fun ViewManager.customView(theme: Int = 0, init: (CustomView).() -> Unit): CustomView {
    return ankoView({ CustomView(it) }, theme, init)
}

Теперь наш CustomView создается очень просто:


customView {
    id = R.id.customview
    // остальные параметры
}

Можно использовать lparams для применения LayoutParams к View.


textView("text") {
        textSize = 12f
    }.lparams(width = matchParent, height = wrapContent) {
        centerInParent()
}

Стоит заметить, что не ко всем View это применимо — все lparams методы как правило объявляются в обертках. Например _RelativeLayout — обертка над RelativeLayout. И так для каждого.


К счастью, для Android Support Library написано несколько оберток, поэтому можно только подключить зависимости в gradle файле.


    // Appcompat-v7 (Anko Layouts)
    implementation "org.jetbrains.anko:anko-appcompat-v7:$anko_version"
    implementation "org.jetbrains.anko:anko-coroutines:$anko_version"

    // CardView-v7
    implementation "org.jetbrains.anko:anko-cardview-v7:$anko_version"

    // Design
    implementation "org.jetbrains.anko:anko-design:$anko_version"
    implementation "org.jetbrains.anko:anko-design-coroutines:$anko_version"

    // GridLayout-v7
    implementation "org.jetbrains.anko:anko-gridlayout-v7:$anko_version"

    // Percent
    implementation "org.jetbrains.anko:anko-percent:$anko_version"

    // RecyclerView-v7
    implementation "org.jetbrains.anko:anko-recyclerview-v7:$anko_version"
    implementation "org.jetbrains.anko:anko-recyclerview-v7-coroutines:$anko_version"

    // Support-v4 (Anko Layouts)
    implementation "org.jetbrains.anko:anko-support-v4:$anko_version"

    // ConstraintLayout
    implementation "org.jetbrains.anko:anko-constraint-layout:$anko_version"

Помимо всего прочего, библиотека позволяет более удобную имплементацию различных listener'ов. Небольшой пример из репозитория:


seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
    override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) = Unit
    override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit
    override fun onStopTrackingTouch(seekBar: SeekBar) = Unit
})

и теперь используя Anko


seekBar {
    onSeekBarChangeListener {
        onProgressChanged { seekBar, progress, fromUser ->
            // do something
        }
    }
}

Также некоторые listener'ы поддерживают корутины:


    verticalLayout{
    val anyCoroutineContext = GlobalScope.coroutineContext
    onClick(anyCoroutineContext) {
             //this: CoroutineScope
    }
}

Anko Coroutines


Для безопасной передачи чувствительных к утечкам памяти объектов используется метод asReference. Он базируется над WeakReference и возвращает объект Ref.

verticalLayout{
    val activity = ui.owner
    val activityReference: Ref<AppActivity> = activity.asReference()
    onClick(anyCoroutineContext) {
        ref().doSomething()
    }
}

Допустим, требуется в стандартный ViewPager.OnPageChangeListener добавить поддержку корутин. Сделаем его таким же крутым, как и пример с seekbar'ом.
Во-первых, создаем отдельный класс и наследуемся от ViewPager.OnPageChangeListener.


class CoroutineOnPageChangeListener(
    private val coroutineContext: CoroutineContext = Dispatchers.Main
) : ViewPager.OnPageChangeListener {

}

В переменных будем хранить лямбды, которые будут вызываться ViewPager.OnPageChangeListener.


    private var onPageScrollStateChanged: ((Int, CoroutineContext) -> Unit)? = null
    private var onPageScrolled: ((Int, Float, Int, CoroutineContext) -> Unit)? = null
    private var onPageSelected: ((Int, CoroutineContext) -> Unit)? = null

Реализуем инициализацию для одной из этих переменных (остальные делаются аналогично)


    fun onPageScrollStateChanged(action: ((Int, CoroutineContext) -> Unit)?) {
        onPageScrollStateChanged = action
    }

И в конце имплементируем функцию с таким же названием.


    override fun onPageScrollStateChanged(state: Int) {
        GlobalScope.launch(coroutineContext) {
            onPageScrollStateChanged?.invoke(state, coroutineContext)
        }
    }

Осталось добавить extension функцию, чтобы это все работало


fun ViewPager.onPageChangeListenerCoroutines(init: CoroutineOnPageChangerListener.() -> Unit) {
    val listener = CoroutineOnPageChangerListener()
    listener.init()
    addOnPageChangeListener(listener)
}

И вставляем всё это дело под ViewPager


viewPager {
    onPageChangeListenerCoroutines {
        onPageScrolled { position, offset, pixels, coroutineContext ->
            // делаем что-нибудь полезное в корутине.
        }
    }
}

Полный код тут
class CoroutineOnPageChangeListener(
    private val coroutineContext: CoroutineContext = Dispatchers.Main
) : ViewPager.OnPageChangeListener {

    private var onPageScrollStateChanged: ((Int, CoroutineContext) -> Unit)? = null
    private var onPageScrolled: ((Int, Float, Int, CoroutineContext) -> Unit)? = null
    private var onPageSelected: ((Int, CoroutineContext) -> Unit)? = null

    fun onPageScrollStateChanged(action: ((Int, CoroutineContext) -> Unit)?) {
        onPageScrollStateChanged = action
    }

    fun onPageScrolled(action: ((Int, Float, Int, CoroutineContext) -> Unit)?) {
        onPageScrolled = action
    }

    fun onPageSelected(action: ((Int, CoroutineContext) -> Unit)?) {
        onPageSelected = action
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
        GlobalScope.launch(coroutineContext) {
            onPageScrolled?.invoke(position, positionOffset, positionOffsetPixels, coroutineContext)
        }
    }

    override fun onPageSelected(position: Int) {
        GlobalScope.launch(coroutineContext) {
            onPageSelected?.invoke(position, coroutineContext)
        }
    }

    override fun onPageScrollStateChanged(state: Int) {
        GlobalScope.launch(coroutineContext) {
            onPageScrollStateChanged?.invoke(state, coroutineContext)
        }
    }
}

fun ViewPager.onPageChangeListenerCoroutines(init: CoroutineOnPageChangerListener.() -> Unit) {
    val listener = CoroutineOnPageChangerListener()
    listener.init()
    addOnPageChangeListener(listener)
}

Так же в библиотеке Anko Layouts есть множество полезных методов, таких как переводы в различные метрики.

Поделиться публикацией

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

    +1
    По мне anko неудобно по причине отсутствия адекватного превью, который будет нормально работать и без билда. Так все супер, но это большой недостаток, который мешает просто пипец как работать
      0
      Я тоже использовал anko… Мне не нравилось разнесенный в java ui и логика… анко этот вопрос решала.
      Но билделось очень долго.
      (А потом появился flutter.)
        0
        Ой да ладно
        Прям уж flutter взошел на олимп, нафиг нам нужен kotlin/native sdk (нет)
        Сырой он еще, чтобы что-то серьезное делать как ни крути
          0
          Знаете, скорее не сырой, а молодой, но его вполне можно использовать, или хотя бы стоит к нему присмотреться.
          Касательно kotlin native: пока полная тишина.
          0
          Flutter не интегрируешь в готовый, протестированный ентерпрайз, мед.проекты(где нужна полная стабильность).
          0

          Удобно ли через Anko делаеть более сложный интерфейс и под разные ориентации дисплея?

            0

            К сожалению, не могу судить по этому поводу. Тут уж каждому по разному. С одной стороны верстка xml более наглядна, благодаря тому же WYSIWYG. Но с другой, Kotlin позволяет удобно разбить UI на классы, оборачивать их и т.д.
            Насчет ориентации экрана, возможно, такой метод покажется Вам удобным.

            0
            Программное написание интерфейса это какая то дичь мазохистская, через пару месяцев сам не поймешь где какой элемент описывается, если у экрана больше 10 контролов. В статье какой то Brainkuck… Пока вы на своем котлине будете одну кнопку через 5 фабрик описывать с корутинами и лямбдами, на 1С уже мышкой накидается готовое приложение image
              0
              Смотря как писать
              Если придерживаться адекватной архитектуры и без говнокода, то все ок даже на крупных проектах
              Что-то слабо верится в идиллию с конструктором вашим
              Простой пример, если понадобится какая-н. мелочь, допустим кружок над иконкой нарисовать с счетчиком уведомлений, как вы это сделаете своим конструктором?)
              По-моему, все очевидно, да и к тому же в чужом коде (он должен быть сгенерированным у конструктора) разбираться то еще удовольствие и ни факт, что получится, либо придется костылить (что вероятнее, если код большой)
              Деньги разрабам не так просто платят, уж поверьте
              Потому что далеко с конструктором не уйдешь
              Но я верю, что скоро они по умнеют (ии и прочее), вот тогда начнется веселье
                0
                кружок над иконкой нарисовать с счетчиком уведомлений
                Имеете в виду бейдж? Такого в 1С нет, да. Но это вопрос UX/UI и «шашечек или ехать» — можно вывести уведомления на главный экран, верхнюю/нижнюю панельку, можно исхиртиться заранее заготовленными иконками (1,2,3,4,5+) и т.д. Главное что рабочее приложение интегрированное с бэкэндами фирмы будет готово за неделю и бизнес ощутит пользу.
                Для игрушек и низкоуровневых приложений — Java/Kotlin, для бизнеса и работы с данными — 1С выходит на сцену ))
                Кстати у 1С нет сгенерированного UI-кода, только визуальный конструктор ) Но можно и хардкорно элементы кодом добавлять
                  0
                  Ну для внутреннего пользования может и не надо таких ухищрений, подойдет и набор из коробки
                  Дизайнеры они такие, могут такое придумать, что без натива будет сложно реализовать
                  Для бизнеса видимо реально проще брать готовые решения, чем пилить велосипед, который может и не поехать в итоге или сломаться на середине пути или еще что-н.))
                0
                Ну ну. Писал я на 1с, вроде наше приложение какой то там конкурс выиграло, в магните 2к пользователей используют. Кастома по визуальной части ноль. Полный ноль. Хочешь кастомный интерфейс — html, и то там проблемы и например дравер или тулбар не кастомизируешь. После 1с перешел на котлин и понимаю какие то были мучения. Ну и да, гигантское количество библиотек (в отличии от 1с) — позволяют довольно быстро пилить довольно сильные вещи.

                З.Ы. Если говорить в целом к тому же — в андроиде вполне есть WYSIWYG редактор интерфейса. Впрочем концептуально как раз создание внешнего вида из кода мне больше нравится, про anko не скажу, активно не трогал, но то что сделали во флаттере мне понравилось когда пощупал немного.
                  0
                  Какие например кастомные доработки UI прям жизненно были необходимы в корпоративном приложении? Может просто непривычно что «не тру-Материал» интерфейс и хотелось привычных контролов? Вы писали на старой мобильной платформе или на новой после 8.3.6? Сейчас много добавилось — звук, push, гео, печать, монетизация, отчеты.
                  Тут надо конечно осознавать возможности и оценивать требования — важнее визуальность или функциональность+скорость.
                    0
                    Начинался проект на 8.3.8 где то, когда заканчивался актуальная 8.3.12 была.
                    Если говорить про UI то проблем много было, не сделать на каждый элемент списка свои элементы управления от условий, сами элементы списков почти не кастомизируются, нужно было рисовать деревья в ТЧ и они на МП выглядели ужасно плюс очень часто приходилось говорить что вот так 1сный контрол не кастомизируются и это очень заказчика напрягало. Это конкретно то что было проблемами для нас, но там и изысков в интерфейсе не сказать что много требовалось.
                    Если говорить не про UI — нет работы в фоне (нет аналога нативных механизмов позволяющий к примеру обновления проверять или записывать местоположение даже после перезагрузки устройства или убийства приложения), нет возможности встроить сторонний SDK (СИБ заказчика требовал например через сторонний SDK делать канал связи шифрованный, шифровать базу, иметь возможность удаленно данные вайпнуть, на рут проверять и еще кучу всего). В итоге реализовали это все только частично через аж два нативных приложения рядом и примерно 7-9 месяцев бодались с СИБ чтобы они вообще позволили приложение запустить в прод. Еще что то было, но уже и не помню даже.

                    Еще дополню, вы почему то так написали что функциональности с 1с будет больше и скорость работы будет выше, но это ведь не так. По всем трем пунктам нативная разработка заметно обгоняет 1с.
                      0
                      Скорость я имел в виду разработки а не работы, хотя и работа не медленная совсем. Функциональности больше «из коробки» — у вас сразу есть СУБД и «ORM», визуальный конструктор форм, построение отчетов, полная кроссплатформенность. Внешние компоненты можно писать на C++ и Java. Криптография появилась в 2017 году. Геозоны, обработка двоичных данных, нативная поддержка многооконности — тоже в 2017 в 8.3.10. Удаленно вайпнуть тоже не проблема, по пушу с секретной командой.

                      В общем, 90% потребностей платформа покрывает, остальное можно сделать нативным приложением-службой и общаться с ним. Или внешней компонентой.
                      На ютубе есть презентация с кейсами, там есть примеры как пара 1сников за 2 недели делали для целых заводов приложение и оно работало везде. Если делать нативно — надо привлечь Android+iOS разработчиков, делать свой бэкенд и интеграцию с 1С, потом все это поддерживать… На такое только крупные холдинги решаются, а на 1С можно запилить свое приложение для любого мелкого бизнеса, только идеи подавай
                        0
                        сразу есть СУБД и «ORM»

                        Room или какой нибудь realm подключаются в два чиха. А в том же руме, хоть это и не очень хорошо, можно прям модельки для ретрофита хранить, что позволяет не задумываться о маппинге сеть<->субд объекты.
                        визуальный конструктор форм

                        Есть в нативном андроиде, во флаттере же есть hot reload или flutter studio. И да, визуальный редактор нормальный для 1с только где то год как появился, до этого реальную форму без запуска не увидеть было.
                        построение отчетов
                        — тут пока не знаю, не было необходимости поэтому с библиотеками для всяких диаграмм/таблиц не сильно пока разбирался. Впрочем например в приложении для магнита на 1с у нас отчетов не было.
                        полная кроссплатформенность

                        Флаттер запускается под ios и под андроид, при этом имеет на 99% выглядящий нативным для каждой платформы интерфейс и очень широкие возможности по взаимодействию с нативным кодом.
                        Внешние компоненты можно писать на C++ и Java.

                        У вас был опыт? Потому что по факту это разве что для работы с железом годиться, какой нибудь SDK сторонний не встроить например.
                        Удаленно вайпнуть тоже не проблема, по пушу с секретной командой.

                        Вот только есть нюанс, код выполнится только после того как пользователь на этот пуш нажмет, не раньше. Не говоря уж что например в случае магнита телефон только во внутренней сети изначально должен был работать, без доступа к интернету с FCM.
                        90% потребностей платформа покрывает

                        По факту процентов 50-60. И то только для b2b, в b2c сегменте к тому же дизайну требований гораздо больше.
                        остальное можно сделать нативным приложением-службой и общаться с ним. Или внешней компонентой.
                        И нет, выше писал — не всегда это прокатывает. Тем более это опять же только b2b, для b2c такое решение не подойдет.
                        На ютубе есть презентация с кейсами, там есть примеры как пара 1сников за 2 недели делали для целых заводов приложение и оно работало везде.

                        Мой нынешний коллега подрабатывал до текущего места работы фрилансом и он аналогично собирал простые приложения из готовых библиотек за несколько дней/пару недель. Это только кажется что разработка на 1с сильно быстрее, по факту выигрыш только в самом начале и то потом он начинает исчезать. Не говоря уж про то что если нужно сложное приложение — на 1с можно его из за отсутствия тех же готовых библиотек даже дольше писать. Да и вообще большая часть времени это написание и модификация бизнес логики, например то же приложение для магнита в сумме делалось наверно 1к-2к+ человекочасов.
                        Если делать нативно — надо привлечь Android+iOS разработчиков, делать свой бэкенд и интеграцию с 1С, потом все это поддерживать…

                        Даже если забыть о флаттере и писать чистый натив — на кой черт отдельный бек с интеграцией с 1с? Если можно апи сразу в 1с сделать.
                        На такое только крупные холдинги решаются, а на 1С можно запилить свое приложение для любого мелкого бизнеса, только идеи подавай

                        Ну ну, не забывайте что мелкому бизнесу кроме того чтобы потратиться на разработку (а это скорее всего франч будет с их ценниками) еще нужно будет купить лицензии. При этом какой нибудь фрилансер мелкое приложение на нативе точно так же за неделю сделает и никаких лицензий не нужно будет.
                0
                Room или какой нибудь realm подключаются в два чиха
                А там есть сразу уровень документов, справочников со спецификой этих объектов? Или надо самому написать слой абстракции для каждого вида сущностей? Или постоянно голыми таблицами/классами оперировать?
                визуальный редактор нормальный для 1с только где то год как появился, до этого реальную форму без запуска не увидеть было
                Это откуда такие познания?? Аж посмеялся ) В 1С изначально с 1996 (?) года был визуальный конструктор
                визуальный редактор… Есть в нативном андроиде
                Ну там какая то смесь из визуального редактора и XML-кода, если туда неправильно влезть, визуальный просмотр крашится. К тому же что-то не припомню, чтоб визуальный редактор был соединен с ОRM и ты мог мышкой на форму таскать поля объекта БД. Нативно можно делать приложения типа как 1С, но надо уметь работать со стеком разных продуктов и написать себе мини-ядро для удобной абстракции бизнес-логики. Дальше пойдет быстрее, но это будет свой велосипед, применяемый в рамках студии/разработчика, надо писать к нему документацию, тесты и т.д.
                  0
                  Это откуда такие познания?? Аж посмеялся ) В 1С изначально с 1996 (?) года был визуальный конструктор

                  Может вы забыли, но мы про мобильную платформу сейчас, а для нее редактор появился только недавно.
                  К тому же что-то не припомню, чтоб визуальный редактор был соединен с ОRM и ты мог мышкой на форму таскать поля объекта БД.

                  Не совсем в том виде, но есть data binding+view-model позволяющий практически то же самое. Дополню еще только что нормальным подходом маппить модель из БД или сети на вью слой — считается насколько я знаю только на маленьких проектах. На крупных проектах обычно их наоборот разнести стараются чтобы слои разделить.
                  А там есть сразу уровень документов, справочников со спецификой этих объектов?

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

                  Мыслите шире, приложения «типа как 1С» — не сказать что прям широченная сфера деятельности.
                    +1
                    По-моему, на вкус и цвет товарищей нет. Нравится и удобнее 1C — вперед. У каждой платформы есть свои плюсы и минусы, вопрос только — какая меньше боли принесет при разработке и поддержки (каждый сам решает)

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

                Самое читаемое