トータルテンプレート





犬がプログラマと何の関係もないとき、彼はすべてを自動化し始めます。 私の活動の性質上、多くのコードを作成する必要があります。もちろん、Android Studioのライブラリ、スクリプト、またはテンプレートの形でいくつかの繰り返しを一般化したいと思います。 それらについてお話します。







テンプレート-誰ですか?



Android Studioの観点から見たテンプレートは、JavaおよびXMLコンストラクト(解決するタスクに依存)、およびテンプレートエンジン言語のメタコンストラクトを含む.ftl拡張子を持つファイル(またはファイルセット)です。 この場合のテンプレートエンジンはFreeMarkerで 、その言語はシンプルですが、同時に複雑なテンプレートを書くのに十分なほど強力です。



アクティビティ、フラグメント、サービス、ウィジェット、UIコンポーネント、ディレクトリなど、さまざまなテンプレートが既に用意されています。 ただし、既存のテンプレートでは不十分なため、独自のテンプレートを作成する必要がある場合があります(当社のような)。 そして、ここで私たちは最初の「驚き」に打たれます。この事件に関する情報はほとんどありません。 GoogleGitの腸から抽出されたいくつかのブログ記事と奇跡的に乏しいドキュメントがあります。



領土の検査



例から学ぶことをお勧めします。そのため、かなり単純ですが、同時に重要な側面を含む空のフラグメントのテンプレートを分析します。 ANDROID_STUDIO_DIR / plugins / android / lib / templates / other / BlankFragmentから取得できます。 実験で何も壊さないように、このディレクトリの内容をどこかにコピーすることをお勧めします。 まず、そこにあるものを把握しましょう。





各ファイルで何が起こるかを理解するのは簡単です。 問題は、その中で何が起こっているのかをカスタマイズする必要がある場合や、独自の何かをゼロから書く必要がある場合に始まります。 公式のドキュメントが少し役立つかもしれません。



そして、実際の例はどこにありますか?!



BlankFragmentテンプレートのニュアンスを理解することは、戦いの半分に過ぎません。 得られた知識を統合するには、自分で何かをする必要があります。 誰が自分のオプションを思い付くのが面倒なのか、彼らは私のものを取ることができます。 残りは見ていて、インスピレーションを受けています。



私たちのアプリケーションでは、各フラグメントがビューであり、すべてのビューがプレゼンターを必要とするMVPアーキテクチャを使用しています。 モデルレイヤーに関係するすべてのものを脇に置き、クラスを計算します。



一見、それほどではありません。 しかし、実際にこれを想像すると、すべてがそれほどバラ色ではありません。 フラグメントとそのマークアップを作成し、このマークアップをフラグメントに登録し、Viewインターフェイスを設計し、このインターフェイスを空のメソッドの形式で実装する必要があります。 同じことをPresenterで行う必要があります。 しかし、これはまだパッケージに分散する必要があります。プロジェクトをクラスの1レベルの地獄にしたくないのですか? また、ViewとPresenterを接続する必要があります。これには、手作業でコードを記述する必要もあります。 もちろん、あなたはこれらすべてで生きることができますが、そのようなルーチンはすぐに気になります。 ここでテンプレートが役立ちます。 彼らの助けを借りて、これらすべての日常的なアクションを自動化して、アーキテクチャの断片を作成します。



とげを通して星へ



template.xmlファイルを実装することから始めましょう。 アクティビティ、フラグメントなどを作成するときに美しいウィンドウに表示されるのはそのコンテンツです。 最も単純なパスに沿って進み、既存のEmptyActivityテンプレートに基づいてMVPテンプレートを作成します。 このディレクトリを自分自身にコピーし、名前をMVPActivityに変更して、 template.xmlファイルを次の形式にします。



template.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" />
      
      





これはチェックボックスの形で表示され、特定のコンポーネントの生成を有効/無効にすることができます。 次に、ビューとプレゼンターのクラスとインターフェースの名前を入力するフィールドが追加されました。



  <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が割り当てられ、このフィールドの表示を担当します。 主な魔法はサジェスト属性で発生します。 ここでは、すべての下線を削除し、接尾辞「Activity」を切り取り、接尾辞「View」を追加します。 このファイルの残りの内容については、疑問は生じないはずです。



今では、アーキテクチャコンポーネントテンプレートの番です。 覚えているように、これらすべてをroot / srcディレクトリに配置する必要があります。 カタログを次のように編成します。



その後、テンプレートファイルを直接処理できます。 基本テンプレートから継承した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> mPresenter = new ${presenterImplName}(this); </#if> } <#if generatePresenter> @Override protected void onDestroy() { mPresenter.onDestroy(); super.onDestroy(); } </#if> }
      
      







ソースファイルとの主な違いは、Viewインターフェイスの実装が追加されることと、Presenterの作成と破棄が追加されることです。 これらを以前はオプションにしたため、これは条件<#if> ... </#if>の形式でテンプレートコードに反映されました。



ここで、タスクはもう少し複雑です。テンプレートファイルを最初から作成します。 しかし、心配しないでください、以前に得た知識はこの問題を解決するのに十分すぎるほどです。 次のようなものが必要です。



SimpleView.java.ftl
 package ${packageName}.presentation.view; public interface ${viewName} { }
      
      







SimplePresenter.java.ftl
 package ${packageName}.presentation.presenter; public interface ${presenterName} { void onDestroy(); }
      
      







SimplePresenterImpl.java.ftl
 package ${packageName}.presentation.implementation; import ${packageName}.presentation.view.${viewName}; import ${packageName}.presentation.presenter.${presenterName}; public class ${presenterImplName} implements ${presenterName} { private ${viewName} mView; public ${presenterImplName}(final ${viewName} view) { mView = view; } @Override public void onDestroy() { mView = null; } }
      
      







もちろん、これらのファイルはそれぞれ独自のパッケージに含まれている必要があります。 材料の準備ができたので、これらすべてのためのレシピが必要です。



recipe.xml.ftl
 <?xml version="1.0"?> <recipe> <#include "../common/recipe_manifest.xml.ftl" /> <#if generateLayout> <#include "../common/recipe_simple.xml.ftl" /> <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" /> </#if> <instantiate from="root/src/app_package/ui/activity/SimpleActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/ui/activity/${activityClass}.java" /> <open file="${escapeXmlAttribute(srcOut)}//ui/activity/${activityClass}.java" /> <#if generateView> <instantiate from="root/src/app_package/presentation/view/SimpleView.java.ftl" to="${escapeXmlAttribute(srcOut)}/presentation/view/${viewName}.java" /> <open file="${escapeXmlAttribute(srcOut)}/presentation/view/${viewName}.java" /> </#if> <#if generatePresenter> <instantiate from="root/src/app_package/presentation/presenter/SimplePresenter.java.ftl" to="${escapeXmlAttribute(srcOut)}/presentation/presenter/${presenterName}.java" /> <open file="${escapeXmlAttribute(srcOut)}/presentation/presenter/${presenterName}.java" /> </#if> <#if generatePresenterImpl> <instantiate from="root/src/app_package/presentation/implementation/SimplePresenterImpl.java.ftl" to="${escapeXmlAttribute(srcOut)}/presentation/implementation/${presenterImplName}.java" /> <open file="${escapeXmlAttribute(srcOut)}/presentation/implementation/${presenterImplName}.java" /> </#if> </recipe>
      
      







元のファイルとは異なり、アーキテクチャコンポーネントのオプションのインスタンス化がここに追加されます。 globals.xml.ftlファイルは変更せずにそのままにしておきます。自分で絵を描くこともできます。



終わり



これにより、テンプレートの作成は完了したと見なすことができます。 結果を見てみましょう。 これを行うには、 ANDROID_STUDIO_DIR / plugins / android / lib / templates / activityに踏み込んで、MVPActivityテンプレートを含むディレクトリをコピーします。 スタジオを開始し、[ファイル]-> [新規]に移動して、新しいMVPカテゴリを探し、そこからテンプレートを開いて結果を喜ばせます。



そして、何らかの理由で記事の本文中のリンクを見逃した人のために、私はそれらを一般的なリストとしてここに挙げます:




All Articles