因?yàn)闀簳r(shí)還沒有考慮好順序,先用A表示
前言
自己也沒有怎么接觸過android studio的模版
只是參考 鴻洋 的博客,接觸到了, 自己記錄一下
具體參考:
https://github.com/WanAndroid/AndroidStudioTemplates
(后面
http://robusttechhouse.com/tutorial-how-to-create-custom-android-code-templates/
里面有說 用 freemarker ,最后生成java代碼, freemarker記得之前的公司,Spring的頁(yè)面有用到,感覺頁(yè)面填充數(shù)據(jù)都差不多)
參考網(wǎng)站
鴻洋博客指向的github地址
https://github.com/WanAndroid/AndroidStudioTemplates
參考的是
- http://blog.csdn.net/lmj623565791/article/details/51635533
- http://www.i-programmer.info/professional-programmer/resources-and-tools/6845-android-adt-template-format-document.html
- https://developer.android.com/studio/projects/templates.html
- http://robusttechhouse.com/tutorial-how-to-create-custom-android-code-templates/
自己參考
先參考
簡(jiǎn)單說明


這里大體的意思是,
通過開始做的參數(shù),去做 recipe的執(zhí)行
執(zhí)行是將【前面的參數(shù)】,【recipe模版】和【Activity模版】,通過FreeMarker生成對(duì)應(yīng)的 java文件
android studio中模版的位置
在 AndroidStudioXXXPath\plugins\android\lib\templates\中, 有對(duì)應(yīng)的代碼
以Activity為例:
我們打開android studio后, 在 File -- New -- Activity 中,可以看見很多可以選的Activity, 會(huì)顯示顯示符合條件的Activity模版

AndroidStudioXXXPath\plugins\android\lib\templates\activities 中,有

我們可以對(duì)比,基本一樣的(文件夾中,有幾個(gè)沒有顯示而已)
對(duì)應(yīng)的文件
我們以 EmptyActivity 為例:
(因?yàn)樽约翰聹y(cè), 空的應(yīng)該是最簡(jiǎn)單的)

我們可以看見,對(duì)應(yīng)的結(jié)構(gòu)
大體為:
- root 文件夾
- 2個(gè)ftl模版文件
- 1個(gè)xml文件
- 一張圖片
我們用大圖看一下

在把miniSdk, 新建 EmptyActivity , 可以看見對(duì)應(yīng)的頁(yè)面

(對(duì)應(yīng)的圖片,和文件夾中的圖片是一樣的)
EmptyActivity 文件概要
- root 文件夾
- 2個(gè)ftl模版文件
- 1個(gè)xml文件
- 一張圖片
我們先看一下
template.xml
<?xml version="1.0"?>
<template
format="5"
revision="5"
name="Empty Activity"
minApi="7"
minBuildApi="14"
description="Creates a new empty activity">
<category value="Activity" />
<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="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="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>
一半猜測(cè),一半看文檔吧
先自己猜測(cè)一下(感覺代碼都是差不多的,很多時(shí)候好的結(jié)構(gòu),可以猜到大概)
這是一個(gè)標(biāo)準(zhǔn)的xml
最外面 template, 可以猜測(cè)到
- name: 名字, Empty Activity,新建的時(shí)候,顯示的內(nèi)容
- minApi:最低api的版本(我們可以發(fā)現(xiàn),gradle對(duì)應(yīng)的版本如果寫得過低,對(duì)應(yīng)的模版是灰色不能選擇的)
- minBuildApi:最低的編譯版本(同上)
- description:描述,應(yīng)該是顯示在對(duì)話框中顯示的描述
其他的變量:
category:類型,這里是 Activity
thumbs:android,java,maven都會(huì)見過,對(duì)應(yīng)的thumbnail,縮略圖,這里指向當(dāng)前文件夾的一個(gè)文件(我們可以發(fā)現(xiàn),如果修改名字后,新建模版就不會(huì)顯示圖片了)
globals:globals.xml.ftl,主觀感覺,應(yīng)該是一些全局的變量或者文件
execute:recipe.xml.ftl,主觀感覺,應(yīng)該是執(zhí)行相關(guān)的
其他parameter們:
parameter:自己感覺就是對(duì)應(yīng)的變量,別的地方可以使用的
一共有的parameter(3個(gè)string類型, 2個(gè)boolean類型)
- activityClass: string 【Activity Name】
- generateLayout:boolean【Generate Layout File】
- layoutName:string 【Layout Name】
- isLauncher:boolean【Launcher Activity】
- packageName:string 【Package name】

對(duì)應(yīng)一下,上圖
發(fā)現(xiàn)全部可以對(duì)應(yīng)上, 并且默認(rèn)值,可以里面的默認(rèn)值是一樣的
globals.xml.ftl
<?xml version="1.0"?>
<globals>
<global id="hasNoActionBar" type="boolean" value="false" />
<global id="parentActivityClass" value="" />
<global id="simpleLayoutName" value="${layoutName}" />
<global id="excludeMenu" type="boolean" value="true" />
<global id="generateActivityTitle" type="boolean" value="false" />
<#include "../common/common_globals.xml.ftl" />
</globals>
前面幾個(gè) global id,應(yīng)該都是 參數(shù)map,存放對(duì)應(yīng)的id,type和value
最后有一個(gè)include
android,或者h(yuǎn)tml頁(yè)面,都經(jīng)常用到的關(guān)鍵字
我們找一下對(duì)應(yīng)的位置: ../common/common_globals.xml.ftl
( 無論是linux,php,win,貌似都一樣,/ 開頭,表示絕對(duì)路徑; 其他表示相對(duì)路徑)
我們到父文件夾找到common文件夾
找到對(duì)應(yīng)的文件

common_globals.xml.ftl
<globals>
<#assign theme=getApplicationTheme()!{ "name": "AppTheme", "isAppCompat": true }>
<#assign themeName=theme.name!'AppTheme'>
<#assign themeNameNoActionBar=theme.nameNoActionBar!'AppTheme.NoActionBar'>
<#assign appCompat=theme.isAppCompat!false>
<#assign appCompatActivity=appCompat && (buildApi gte 22)>
<global id="themeName" type="string" value="${themeName}" />
<global id="implicitParentTheme" type="boolean" value="${(themeNameNoActionBar?starts_with(themeName+'.'))?string}" />
<global id="themeNameNoActionBar" type="string" value="${themeNameNoActionBar}" />
<global id="themeExistsNoActionBar" type="boolean" value="${(theme.existsNoActionBar!false)?string}" />
<global id="themeNameAppBarOverlay" type="string" value="${theme.nameAppBarOverlay!'AppTheme.AppBarOverlay'}" />
<global id="themeExistsAppBarOverlay" type="boolean" value="${(theme.existsAppBarOverlay!false)?string}" />
<global id="themeNamePopupOverlay" type="string" value="${theme.namePopupOverlay!'AppTheme.PopupOverlay'}" />
<global id="themeExistsPopupOverlay" type="boolean" value="${(theme.existsPopupOverlay!false)?string}" />
<global id="appCompat" type="boolean" value="${((isNewProject!false) || (theme.isAppCompat!false))?string}" />
<global id="appCompatActivity" type="boolean" value="${appCompatActivity?string}" />
<global id="hasAppBar" type="boolean" value="${appCompatActivity?string}" />
<global id="hasNoActionBar" type="boolean" value="${appCompatActivity?string}" />
<global id="manifestOut" value="${manifestDir}" />
<global id="buildVersion" value="${buildApi}" />
<#if !appCompat>
<global id="superClass" type="string" value="Activity"/>
<global id="superClassFqcn" type="string" value="android.app.Activity"/>
<global id="Support" value="" />
<global id="actionBarClassFqcn" type = "string" value="android.app.ActionBar" />
<#elseif appCompatActivity>
<global id="superClass" type="string" value="AppCompatActivity"/>
<global id="superClassFqcn" type="string" value="android.support.v7.app.AppCompatActivity"/>
<global id="Support" value="Support" />
<global id="actionBarClassFqcn" type = "string" value="android.support.v7.app.ActionBar" />
<#else>
<global id="superClass" type="string" value="ActionBarActivity"/>
<global id="superClassFqcn" type="string" value="android.support.v7.app.ActionBarActivity"/>
<global id="Support" value="Support" />
<global id="actionBarClassFqcn" type = "string" value="android.support.v7.app.ActionBar" />
</#if>
<global id="srcOut" value="${srcDir}/${slashedPackageName(packageName)}" />
<global id="resOut" value="${resDir}" />
<global id="menuName" value="${classToResource(activityClass!'')}" />
<global id="simpleName" value="${activityToLayout(activityClass!'')}" />
<global id="relativePackage" value="<#if relativePackage?has_content>${relativePackage}<#else>${packageName}</#if>" />
</globals>
我們可以發(fā)現(xiàn)更多的global參數(shù),存放的map值
recipe.xml.ftl
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/SimpleActivity.java.ftl"
to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
<open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />
</recipe>
我們發(fā)現(xiàn)被 recipe 包裹,
有2個(gè)#include, 也就是對(duì)應(yīng) 父文件夾下common文件夾的recipe_manifest.xml.ftl,recipe_simple.xml.ftl,對(duì)應(yīng)的文件
(具體就不跟了,應(yīng)該也是添加對(duì)應(yīng)的recipe相關(guān)的內(nèi)容)第2個(gè)include前面,有一個(gè) #if, 應(yīng)該是判斷, 后面這個(gè)字符串,如果大家觀察前面文件仔細(xì)的話,在template.xml的parameter中有對(duì)應(yīng)的值,默認(rèn)為true
后面大體應(yīng)該是打開文件,創(chuàng)建文件等操作, 創(chuàng)建實(shí)例
<instantiate from="root/src/app_package/SimpleActivity.java.ftl"
to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" />就是
應(yīng)該就是打開 root下面唯一的SimpleActivity.java.ftl 模版文件,復(fù)制到對(duì)應(yīng)template.xml的parameter為activityClass的值的文件中
簡(jiǎn)單總結(jié)
還是最上面的圖


第一個(gè)圖:
通過開始做的參數(shù),去做 recipe的執(zhí)行
也就是,在 template.xml 顯示界面,并且獲得對(duì)應(yīng)參數(shù)的value,和globals.xml.ftl里面的value一起去做Recipe執(zhí)行操作
第二個(gè)圖:
執(zhí)行是將【前面的參數(shù)】,【recipe模版】和【Activity模版】,通過FreeMarker生成對(duì)應(yīng)的 java文件
這里圖中 MyActivity.java.ftl 就是 上面例子中 SimpleActivity.java.ftl 文件