Тотальное Шаблонирование



Тотальное шаблонирование

Когда собаке-программисту нечего делать, он начинает все автоматизировать.

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



Шаблоны – кто они?

Шаблон в терминах Android Studio — это файл (или набор файлов) с расширением .

ftl , содержащий конструкции на Java и XML (в зависимости от решаемой задачи), а также метаконструкции на языке шаблонизатора.

Шаблонизатор в нашем случае FreeMarker , чей язык прост, но в то же время достаточно мощный для написания сложных шаблонов.

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

Но бывают случаи (как наш), когда существующих шаблонов недостаточно и нужно сделать свой.

И тут нас поджидает первый «сюрприз»: информации по этому делу очень мало.

Есть несколько статей в блогах и немногочисленная документация, чудесным образом извлеченная из глубин GoogleGit.

Осмотр территории

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

Вы можете получить его от ANDROID_STUDIO_DIR/plugins/android/lib/templates/other/BlankFragment .

Содержимое этого каталога лучше скопировать куда-нибудь, чтобы ничего не сломать своими экспериментами.

Для начала посмотрим, что там.

  • globals.xml.ftl — набор глобальных переменных для шаблона
  • корень/res/layout/fragment_blank.xml.ftl — шаблон разметки фрагмента
  • корень/рез/значения/strings.xml — строковые константы, которые будут добавлены в проект
  • корень/src/app_package/BlankFragment.java.ftl - шаблон кода
  • шаблон.

    xml - метаданные шаблона

  • template_blank_fragment.png - самый важный файл! Значок фрагмента в данном случае
Нетрудно понять, что происходит в каждом из файлов.

Проблемы начинаются тогда, когда возникает необходимость настроить происходящее в них или даже написать что-то свое с нуля.

Немного помощи с этим официальная документация

Где реальные примеры?!

Понимание нюансов шаблона BlankFragment — это только полдела.

Чтобы закрепить полученные знания, нужно сделать что-то свое.

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

Другие смотрят и вдохновляются.

В наших приложениях мы используем архитектуру MVP, согласно которой каждый фрагмент является View, а каждому View нужен Presenter. Оставим в стороне все, что связано со слоем Модель, и посчитаем классы:

  • ФрагментВью + ВьюИнтерфейс
  • ФрагментПрезентер + ПрезентерИнтерфейс
На первый взгляд, не так уж и много.

Но если применить это на практике, все окажется не так радужно.

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

То же самое придется сделать и с Ведущим.

Но это еще нужно распределить по пакетам; вы ведь не хотите, чтобы ваш проект был одноуровневым адом для занятий, верно? Также необходимо подключить View и Presenter, что также требует написания кода вручную.

Конечно, со всем этим можно жить, но такая рутина быстро надоедает. Здесь на помощь приходят шаблоны.

С их помощью мы автоматизируем все эти рутинные действия по созданию архитектурных произведений.



Через тернии к звездам

Начнем с реализации файла template.xml. Именно его содержимое вы видите в красивых окнах при создании активностей, фрагментов и т. д. Мы пойдем самым простым путем и сделаем наш шаблон MVP на основе существующего шаблона EmptyActivity. Копируем этот каталог себе, переименовываем его в MVPActivity и предоставляем файл шаблон.

xml к следующей форме: шаблон.

xml

  
  
  
   

<Эxml version="1.0"?> <template format="5" revision="1" name="MVP Activity" minApi="7" minBuildApi="14" description="Creates a new MVP activity"> <category value="MVP" /> <formfactor value="Mobile" /> <parameter id="activityClass" name="Activity Name" type="string" constraints="class|unique|nonempty" suggest="${layoutToActivity(layoutName)}" default="MainActivity" help="The name of the activity class to create" /> <parameter id="generateLayout" name="Generate Layout File" type="boolean" default="true" help="If true, a layout file will be generated" /> <parameter id="generateView" name="Generate View" type="boolean" default="true" help="If true, a View interface will be generated" /> <parameter id="generatePresenter" name="Generate Presenter?" type="boolean" default="true" help="If true, a Presenter interface will be generated" /> <parameter id="generatePresenterImpl" name="Generate Presenter implementation?" type="boolean" default="true" help="If true, a Presenter implementation will be generated" /> <parameter id="layoutName" name="Layout Name" type="string" constraints="layout|unique|nonempty" suggest="${activityToLayout(activityClass)}" default="activity_main" visibility="generateLayout" help="The name of the layout to create for the activity" /> <parameter id="isLauncher" name="Launcher Activity" type="boolean" default="false" help="If true, this activity will have a CATEGORY_LAUNCHER intent filter, making it visible in the launcher" /> <parameter id="viewName" name="View Name" type="string" constraints="class|nonempty|unique" default="MainView" visibility="generateView" suggest="${underscoreToCamelCase(classToResource(activityClass))}View" help="The name of the View interface to create" /> <parameter id="presenterName" name="Presenter Name" type="string" constraints="class|nonempty|unique" default="MainPresenter" visibility="generatePresenter" suggest="${underscoreToCamelCase(classToResource(activityClass))}Presenter" help="The name of the Presenter interface to create" /> <parameter id="presenterImplName" name="Presenter Implementation Name" type="string" constraints="class|nonempty|unique" default="MainPresenterImpl" visibility="generatePresenterImpl" suggest="${underscoreToCamelCase(classToResource(activityClass))}PresenterImpl" help="The name of the presenter implementation class to create" /> <parameter id="packageName" name="Package name" type="string" constraints="package" default="com.mycompany.myapp" /> <!-- 128x128 thumbnails relative to template.xml --> <thumbs> <!-- default thumbnail is required --> <thumb>template_blank_activity.png</thumb> </thumbs> <globals file="globals.xml.ftl" /> <execute file="recipe.xml.ftl" /> </template>

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

Во-первых, были добавлены блоки формы:

<parameter id="generateView" name="Generate View" type="boolean" default="true" help="If true, a View interface will be generated" />

Которые будут отображаться в виде флажков, позволяющих включать/отключать генерацию тех или иных компонентов.

Во-вторых, добавлены поля для ввода названий классов и интерфейсов View и Presenters:

<parameter id="viewName" name="View Name" type="string" constraints="class|nonempty|unique" default="MainView" visibility="generateView" suggest="${underscoreToCamelCase(classToResource(activityClass))}View" help="The name of the View interface to create" />

Обязательно обратите внимание на атрибут видимость .

Именно в нем прописывается id чекбокса, который отвечает за отображение этого поля.

Основная магия происходит в атрибуте предлагать .

Здесь мы удалим все возможные символы подчеркивания, отрежем суффикс «Активность» и добавим собственный суффикс «Вид».

К остальному содержимому этого файла, думаю, вопросов возникнуть не должно.

Теперь пришло время шаблонов архитектурных компонентов.

Как мы помним, всё это нужно расположить в каталоге корень/источник .

Мы организуем каталог следующим образом:

  • корень/источник
    • app_package
      • презентация
        • выполнение
        • ведущий
        • вид
      • пользовательский интерфейс
        • активность
После этого вы можете работать непосредственно с файлами шаблона.

Давайте начнем с SimpleActivity.java.ftl , который мы унаследовали от базового шаблона.

Его необходимо переместить в каталог ui/activity и преобразовать к следующему виду: SimpleActivity.java.ftl

package ${packageName}.

ui.activity; import ${superClassFqcn}; import android.os.Bundle; import ${packageName}.

R; <#if generateView>import ${packageName}.

presentation.view.${viewName};</#if> <#if generatePresenter>import ${packageName}.

presentation.presenter.${presenterName};</#if> <#if generatePresenterImpl>import ${packageName}.

presentation.implementation.${presenterImplName};</#if> public class ${activityClass} extends ${superClass} <#if generateView>implements ${viewName}</#if>{ <#if generatePresenter> private ${presenterName} mPresenter; </#if> @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); <#if generateLayout> setContentView(R.layout.${layoutName}); </#if> <#if generatePresenterImpl>

Теги: #Разработка для Android #Разработка мобильных приложений #java #разработка для Android #Android Studio #freemarker

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.