Поживём-увидим, но для андроид-разработки сейчас не использовать Котлин — можно, но не нужно. Ещё раз уточню, что одна из основных причин — это доступность фишек, которые на андроид-платформе недоступны в силу ограниченной поддержки фишек из новых версий Java.
Хочешь, например, Optional? А фиг тебе, только начиная с API 24.
Ну и сам язык просто приятен.
А из альтернатив для больших систем — так ведь Scala есть, и Тинькофф, и Сбер на ней много что делают, и не плачут, кстати.
Вот тут хз. Как и в случае Java, основной интерес ведь представляет не сам язык, а инфраструктура, которая выросла вокруг этого языка. Если не было бы J2EE, Spring, Hibernate (тут продолжаем список) — кому интересна была бы Java? Мало кому.
Насчёт Flutter, насколько я вижу, сейчас ситуация упирается как раз в его окружение.
Если для андроида + Java/Kotlin у меня есть куча инструментов — Dagger, Realm, Architecture Components, Retrofit, Rx и реально куча всего разного, без чего полноценные приложения делать сложно, то вот для Flutter…
Для меня реально интересно было бы посмотреть на человека, который сейчас начинал бы писать новый проект на андроиде, используя Java, а не Котлин.
Сами на Котлине, в проде, причём давно.
Куча приложений в проде, написанных на Котлине — часть из них попала в прод ещё до того, как Гугл объявил о поддержке Котлина.
Не знаю, как на других платформах (энтерпрайз, веб и проч.), но на андроиде это реальный мейнстрим. По куче разных причин, основная из которых — отсутствие плюшек из новых версий Java для андроид-девелоперов.
Вот извечная печаль андроид-разработки — когда визуально простое поведение требует ну совсем нетривиальных решений… И расскажи это потом заказчику, отчего у тебя куча времени ушла на какую-то ерунду…
Спасибо, интересно почитать.
В рантайме зависимости, конечно, страшновато — но это смотреть по статистике надо. На 20 млн пользователей её удобно набирать :)
В Кодеине есть какая-нибудь поддержка, аналогичная subcomponent-ам в Даггере? Очень уж удобно с ними ненужные объекты за собой убирать.
> Актуализация информации в столбце для GMaps — враньё. Особенно в России
Могу сказать конкретно за Новоуральск, Гугл и Яндекс. Так вот, Гугл наш город знает куда лучше, чем Яндекс — особенно это актуально стало в контексте замены Uber (который использовал гугло-карты) на Яндекс-такси.
Имхо стоит сразу описать использование JobIntentService — при условии, что хочется сохранить поведение в стиле IntentService — либо отрефакторить приложение, избавиться от IntentService целиком, переведя управление заданиями полностью на JobScheduler/JobService.
В противном случае нет ясности относительно jobFinished (в который ещё и JobParameters передать как-то надо).
Можно, но в этом случае наблюдается другое поведение по сравнению с EditText.error: надпись об ошибке показывается под контролом, без маркера, и автоматически не пропадает при изменении текста в поле ввода.
Я поиграл, и пришёл к выводу, что цепочку инициализации всё-таки лучше с Activity начинать.
Если этим занимается presenter, ему нужно дать возможность создать ActivityScoped-компонент.
Для этого ему наверняка понадобятся другие (ApplicationScope) компоненты, уже созданные в Application.
Presenter про Application ничего не знает, значит Activity должна ему передать этот самый Application — либо необходимые компоненты.
Короче, получается некрасиво.
Ну а сам Presenter, как описано где-то в переписке, удобно между пересозданиями Activity в PresenterManager сохранять.
То есть при первом создании активити она создаёт presenter через dagger, а при пересозданиях этой активити — берёт его уже из presenterManager.
Ммм… а там внутри есть Google Play Service-ы? А если нет, то откуда андроид-приложения станут брать геолокацию, карты, работу с пушем, кучу других вещей? Тетрис — да, наверное запустится.
Другими словами, сюда можно устанавливать любые Android-приложения из соответствующих каталогов приложений
Ээээ… а Google Play Services там есть? А если нет, то как можно говорить о «любых андроид-приложениях»?!
На эти самые сервисы же всё интересное завязано — от карт и геолокации до пуш-уведомлений.
А смотрите, в MVP ведь P как раз и отвечает за общение с внешним миром, выполнение запросов, сохранение результатов в БД, обработку ошибок — и проч., поэтому на мой взгляд логично ему и отдать компонент на хранение.
Практик обработки смены ориентации для активити, при которой presenter остаётся жив, несколько, лично мне вот этот подход нравится: http://engineering.remind.com/android-code-that-scales/
С точки зрения реализации особых проблем мне не видится, например так:
1. activity создалась, создался presenter со своими компонентами и зависимостями (или был взят уже ранее созданный в случае смены ориентации)
2. activity говорит: presenter.setView(this), ОК
теперь нужно в активити что-то заинжектить.
Вопрос: а зачем теперь в неё что-то инжектить? Ведь за связь с внешним миром отвечает сам presenter.
Нужно отметить, что правильный презентер сам выполнить inject для активити не сможет: ведь у него есть только интерфейс для активити, а для inject нужен конкретный тип.
Но если вдруг надо, то активити всегда может сделать так
Да, мне кажется, что там им самое место — ведь activity-related-компонент кроме как в контексте данной активити ведь и не нужен никому?
При этом разные DBManager-ы нужны именно Presenter-у, а не самой Activity — он из них что-то загрузил и потом результат в activity отправил.
С другой стороны, если используется простое приложение без MVP, с парой экранов — можно их, компоненты, там в Application и оставить.
Я и предположил, что в Application как раз и приведено создание, чтобы избыточную сложность не добавлять в пример.
Насчёт инициализации screen-related компонентов из Application: меня смущает что получится, если экранов (активити, фрагменты) будет с несколько десятков: будет куча кода, к Application отношения не имеющего. Нарушается Single Responsibility Principle и прочая.
Возможно стоит вынести ответственность за создание таких компонент и за управление их временем жизни в соответствующие Presenters.
Кстати, может быть стоит для удобства восприятия на диаграммах с компонентами где-то рядом с именем класса указывать имя модуля, в котором создаётся его экземпляр? То есть не AppComponent { Context, IDataRepository,… }, а что-нибудь вида
AppComponent { Context (AppModule), IDataRepository (DataModule),… }
Если не указывать, то реально сложно распознать структуру связей между модулями без использования кода под диаграммами.
Хочешь, например, Optional? А фиг тебе, только начиная с API 24.
Ну и сам язык просто приятен.
А из альтернатив для больших систем — так ведь Scala есть, и Тинькофф, и Сбер на ней много что делают, и не плачут, кстати.
Насчёт Flutter, насколько я вижу, сейчас ситуация упирается как раз в его окружение.
Если для андроида + Java/Kotlin у меня есть куча инструментов — Dagger, Realm, Architecture Components, Retrofit, Rx и реально куча всего разного, без чего полноценные приложения делать сложно, то вот для Flutter…
Сами на Котлине, в проде, причём давно.
Не знаю, как на других платформах (энтерпрайз, веб и проч.), но на андроиде это реальный мейнстрим. По куче разных причин, основная из которых — отсутствие плюшек из новых версий Java для андроид-девелоперов.
В рантайме зависимости, конечно, страшновато — но это смотреть по статистике надо. На 20 млн пользователей её удобно набирать :)
В Кодеине есть какая-нибудь поддержка, аналогичная subcomponent-ам в Даггере? Очень уж удобно с ними ненужные объекты за собой убирать.
Могу сказать конкретно за Новоуральск, Гугл и Яндекс. Так вот, Гугл наш город знает куда лучше, чем Яндекс — особенно это актуально стало в контексте замены Uber (который использовал гугло-карты) на Яндекс-такси.
В противном случае нет ясности относительно jobFinished (в который ещё и JobParameters передать как-то надо).
Вот маркеры ошибок:
было в 24.1.1
стало в 24.2.0
Если этим занимается presenter, ему нужно дать возможность создать ActivityScoped-компонент.
Для этого ему наверняка понадобятся другие (ApplicationScope) компоненты, уже созданные в Application.
Presenter про Application ничего не знает, значит Activity должна ему передать этот самый Application — либо необходимые компоненты.
Короче, получается некрасиво.
Ну а сам Presenter, как описано где-то в переписке, удобно между пересозданиями Activity в PresenterManager сохранять.
То есть при первом создании активити она создаёт presenter через dagger, а при пересозданиях этой активити — берёт его уже из presenterManager.
Ээээ… а Google Play Services там есть? А если нет, то как можно говорить о «любых андроид-приложениях»?!
На эти самые сервисы же всё интересное завязано — от карт и геолокации до пуш-уведомлений.
Практик обработки смены ориентации для активити, при которой presenter остаётся жив, несколько, лично мне вот этот подход нравится: http://engineering.remind.com/android-code-that-scales/
С точки зрения реализации особых проблем мне не видится, например так:
1. activity создалась, создался presenter со своими компонентами и зависимостями (или был взят уже ранее созданный в случае смены ориентации)
2. activity говорит: presenter.setView(this), ОК
теперь нужно в активити что-то заинжектить.
Вопрос: а зачем теперь в неё что-то инжектить? Ведь за связь с внешним миром отвечает сам presenter.
Нужно отметить, что правильный презентер сам выполнить inject для активити не сможет: ведь у него есть только интерфейс для активити, а для inject нужен конкретный тип.
Но если вдруг надо, то активити всегда может сделать так
presenter.setView(this);
presenter.getComponent.inject(this);
Как-то вот так.
При этом разные DBManager-ы нужны именно Presenter-у, а не самой Activity — он из них что-то загрузил и потом результат в activity отправил.
С другой стороны, если используется простое приложение без MVP, с парой экранов — можно их, компоненты, там в Application и оставить.
Я и предположил, что в Application как раз и приведено создание, чтобы избыточную сложность не добавлять в пример.
Возможно стоит вынести ответственность за создание таких компонент и за управление их временем жизни в соответствующие Presenters.
AppComponent { Context (AppModule), IDataRepository (DataModule),… }
Если не указывать, то реально сложно распознать структуру связей между модулями без использования кода под диаграммами.
И спасибо за статьи, просто отличные.