Когда собаке-программисту нечего делать, он начинает все автоматизировать.
По роду работы мне приходится писать много кода и, конечно же, некоторые повторяющиеся вещи хочется обобщить в виде библиотек, скриптов или шаблонов для 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
- презентация
- выполнение
- ведущий
- вид
- пользовательский интерфейс
- активность
- презентация
- 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
-
Ноутбук Для Писателя
19 Oct, 24 -
Бумажный Компьютер
19 Oct, 24 -
Игры С Презентации Sony Playstation 5
19 Oct, 24 -
Геймификация В Электронной Коммерции
19 Oct, 24