您好,登錄后才能下訂單哦!
Android Studio模板中怎么使用文件組,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
已有工程中使用模板效果圖
創建工程時使用模板
示例場景
在進行Android開發時,我們經常會創建一個Demo工程,目的可能有很多種,可能是為了驗證一個問題,可能是為了學習一個框架的使用,可能為了測試自己寫的一個lib庫等等。這個時候我們可能會創建一個Activity,然后再在xml寫一些按鈕,再在Activity里寫該按鈕的事件監聽邏輯,也就是說為了執行一段代碼我們要做這么多操作。為了簡化這段重復操作,我這邊寫了一個DebugActivity類,然后支持我們只需要寫個子類來繼承它,然后像下面這樣寫幾個方法即可,運行的時候會根據方法動態創建按鈕,并在點擊按鈕時執行該方法的代碼邏輯。
public void _test() { T("彈出Toast"); }
由于本文主要介紹模板相關的,所以該場景相關的具體代碼技術細節就不多說了,有興趣的可以看下,DebugActivity的代碼,這里提出來只是為模板開發簡單的做個鋪墊。
模板位置
Android Studio Template中有系統預設的一些模板,我們可以直接修改,也可以另行添加新的模板。打開Android Studio安裝目錄/Contents/plugins/android/lib/templates這個文件夾我們能看到下面的目錄結構,這里便是AS中模板存放的位置。
我們接下來的工作也就在這里,保險起見我們在這里新建一個目錄,我們自己寫的模板都放在自己新建的目錄里,例如我這里就創建了一個叫pk的目錄。
模板規范
在上面的基礎上,我們可以直接打開/activies/EmptyActivity目錄,如下圖
我們可以看到上面紅色區域便是Template的文件結構,大致說下各個文件(夾)的含義
globals.xml.ftl 模板中參數配置的地方(可選)
recipe.xml.ftl 模板行為執行處,引入這個模板之后,接下來要做什么事情,就是它說的算(可選,但是不選就沒有意義了,因為模板引入是要要行為驅動的)
root 存放模板文件及引入資源的目錄,模板文件可以是.xml、.java、.gradle等任何一個文本格式的文件,資源一般是我們引入的.png資源文件(可選,不選同上)
template_blank_activity.png 引入模板時的引導圖(可選)
template.xml 面向模板引擎的配置文件(必選)
我們可以看到,真正核心的部分就是root、recipe.xml.ftl和template.xml,接下來這重點說明這三部分。
我們可以打開root目錄,能夠看到里面的文件除了圖片資源文件都是以.ftl結尾的,而.ftl是標準的FreeMarker的文件。FreeMarker是類似于Velocity的一種模板框架,據說對于多文件處理時它具有更好的性能,大概也是Android Studio選擇Velocity作為單文件模板,選擇FreeMarker作為文件組模板的原因吧。有興趣的可以去FreeMarker官網學習一下,它的自定義標簽功能還是很強大的,個人感覺比Velocity的更加接地氣。
接下來我們看一下recipe.xml.ftl 的內容,打開如下
這里以<#開頭的都是FreeMarker的語法,基本上比葫蘆畫瓢就能看明白,就不多說了。其實對于這個文件最重要的部分是下面四個標簽:
copy 就是簡單的copy,把模板root目錄下的某個文件copy到目標工程的某個目錄下
instantiate 跟copy很類似,***多的一點功能就是并不只簡單的走IO流進行copy,而是通過FreeMarker框架按照模板中的FreeMarker能識別的邏輯判斷和數據引入來生成最終的目標文件
merge 目標項目中有了某文件,而我們還要想該文件合并一些我們的模板的部分時,就選用merge,例如我們添加一個Activity時需要mergeAndroidManifest.xml的配置。目前支持的merge格式有.xml和.gradle,但是對.gradle支持的不怎么好,不過不影響該模板的開發,對于這套模板引擎的開發者來說,這可能是最麻煩的部分了,但是對于我們使用者就不用考那么多了,直接使用吧
open 這個很簡單,就是指定模板引入之后要IDE打開的文件
然后看下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>
當我們進行模板引入時,AS會彈出一個如下圖的UI界面,要我們來填入或選擇一些數據,例如輸入Activity的的名稱,選擇SDK的版本之類的。而這個界面就是根據由該文件而來的。
內容比較多,為減少篇幅我挑些重要的說
template標簽
name 引入模板時的模板名稱,就死根據他選擇哪個模板的
description 彈出Dialog的標題,對應上去的區域1
category 表示該模板屬于哪種分類,在引入的時候會有個分類的選擇
parameter 每個該標簽就對應Dialog界面的一個輸入項
id 該參數的***標識符,也是我們在.ftl中引入的值,例如定義的id為username,引用時就是$username
name 對應Dialog上面該輸入項的名稱
type 對應該參數的類型,Dialog就是根據這個來決定對應輸入是選擇框、輸入框還是下拉框等等
constraints 對應該參數的約束,如果有多個要用|分割開
suggest 建議值,這個輸入部分是由級聯效應的,可能你改了A參數,B參數也會跟著改變,就是根據這個參數決定的
default 參數的默認值
visibility 可見性,要配置一個boolean類型的參數,一般指向另一個輸入源
help 當焦點在某個輸入源上面時,上圖的區域3的就限制這兒的內容
操刀實戰
了解了模板規范之后,我們編寫模板時就不會那么被動了,下面我們來自己動手編寫文章開始部分展示的模板。
首先在剛才提到的自定義的模板下創建如下圖所示的目錄結構
然后將下面的代碼對應貼進去(圖片部分隨便找一張代替好了…)
globals.xml.ftl
recipe.xml.ftl
template.xml
<?xml version="1.0"?> <template format="5" revision="5" name="Debug Activity" minApi="7" minBuildApi="14" description="創建一個Debug的Activity"> <category value="Activity" /> <formfactor value="Mobile" /> <parameter id="activityClass" name="Activity名稱" type="string" constraints="class|unique|nonempty" default="SetupActivity" help="創建Activity的名稱" /> <parameter id="addExample" name="是否添加按鈕使用示例" type="boolean" default="false" help="選擇時會自動生成測試按鈕;否則不生成" /> <parameter id="addJumpActivity" name="是否添加跳轉Activity示例" type="boolean" default="false" help="選擇時會自動生成跳轉Activity相關邏輯;否則不生成" /> <parameter id="isLauncher" name="設為啟動頁面" type="boolean" default="true" help="選擇時設置該頁面為啟動頁面;否則不設" /> <parameter id="packageName" name="包名" type="string" constraints="package" default="com.mycompany.myapp" help="輸入Application包名" /> <!-- 128x128 thumbnails relative to template.xml --> <thumbs> <!-- default thumbnail is required --> <thumb>template_debug_activity.png</thumb> </thumbs> <globals file="globals.xml.ftl" /> <execute file="recipe.xml.ftl" /> </template>
AndroidManifest.xml.ftl
DebugActivity.java.ftl
package ${packageName}; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.Toast; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * Debug測試類,快速調試Demo工程<hr /> * 使用姿勢:<br /> * 1. 新建一個子類繼承該類<br /> * 2. 跳轉Activity: 在子類配置{@link Jump}注解, 然后在注解中配置跳轉Activity的類型<br /> * 3. 點擊按鈕觸發方法: 在子類聲明一個名稱以"_"開頭的方法(支持任意修飾符),最終生成按鈕的文字便是改方法截去"_"<br /> * 4. 方法參數支持缺省參數和單個參數<br /> * 5. 如果是單個參數,參數類型必須是Button或Button的父類類型,當方法執行時,該參數會被賦值為該Buttom對象<br /> * https://github.com/puke3615/DebugActivity<br /> * <p> * * @author zijiao * @version 16/10/16 */ public abstract class DebugActivity extends Activity { protected static final String FIXED_PREFIX = "_"; private final String TAG = getClass().getName(); private final List<ButtonItem> buttonItems = new ArrayList<>(); protected LinearLayout linearLayout; protected Context context; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Jump { Class<? extends Activity>[] value() default {}; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.context = this; ScrollView scrollView = new ScrollView(this); setContentView(scrollView); this.linearLayout = new LinearLayout(this); this.linearLayout.setOrientation(LinearLayout.VERTICAL); scrollView.addView(linearLayout); try { resolveConfig(); createButton(); } catch (Throwable e) { error(e.getMessage()); } } private void createButton() { for (ButtonItem buttonItem : buttonItems) { linearLayout.addView(buildButton(buttonItem)); } } protected View buildButton(final ButtonItem buttonItem) { final Button button = new Button(this); button.setText(buttonItem.name); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (buttonItem.target != null) { to(buttonItem.target); } else { Method method = buttonItem.method; method.setAccessible(true); Class<?>[] parameterTypes = method.getParameterTypes(); int paramSize = parameterTypes.length; switch (paramSize) { case 0: try { method.invoke(DebugActivity.this); } catch (Throwable e) { e.printStackTrace(); error(e.getMessage()); } break; case 1: if (parameterTypes[0].isAssignableFrom(Button.class)) { try { method.invoke(DebugActivity.this, button); } catch (Throwable e) { e.printStackTrace(); error(e.getMessage()); } break; } default: error(method.getName() + "方法參數配置錯誤."); break; } } } }); return button; } private void resolveConfig() { Class<?> cls = getClass(); //讀取跳轉配置 if (cls.isAnnotationPresent(Jump.class)) { Jump annotation = cls.getAnnotation(Jump.class); for (Class<? extends Activity> activityClass : annotation.value()) { buttonItems.add(buildJumpActivityItem(activityClass)); } } //讀取方法 for (Method method : cls.getDeclaredMethods()) { handleMethod(method); } } protected void handleMethod(Method method) { String methodName = method.getName(); if (methodName.startsWith(FIXED_PREFIX)) { methodName = methodName.replaceFirst(FIXED_PREFIX, ""); ButtonItem buttonItem = new ButtonItem(); buttonItem.method = method; buttonItem.name = methodName; buttonItems.add(buttonItem); } } protected ButtonItem buildJumpActivityItem(Class<? extends Activity> activityClass) { ButtonItem buttonItem = new ButtonItem(); buttonItem.name = "跳轉到" + activityClass.getSimpleName(); buttonItem.target = activityClass; return buttonItem; } public void L(Object s) { Log.i(TAG, s + ""); } public void error(String errorMessage) { T("[錯誤信息]\n" + errorMessage); } public void T(Object message) { Toast.makeText(context, String.valueOf(message), Toast.LENGTH_SHORT).show(); } public void to(Class<? extends Activity> target) { try { startActivity(new Intent(this, target)); } catch (Exception e) { e.printStackTrace(); error(e.getMessage()); } } public void T(String format, Object... values) { T(String.format(format, values)); } protected static class ButtonItem { public String name; public Method method; public Class<? extends Activity> target; } }
JumpActivity.java.ftl
SimpleActivity.java.ftl
package ${packageName}; @DebugActivity.Jump({ <#if addJumpActivity> JumpActivity.class, <#else> </#if> }) public class ${activityClass} extends DebugActivity { <#if addExample> private int number = 0; public void _無參方法調用() { T("無參方法調用"); } public void _有參方法調用(Button button) { button.setText("number is " + number++); } //代碼執行不到,直接彈出toast提示報錯 public void _錯誤參數調用(String msg) { T("test"); } //方法名沒有以"_"開頭,按鈕無法創建成功 public void 無效調用() { T("test"); } //crash會被會被catch住,以toast方式彈出 public void _Crash測試() { int a = 1 / 0; } </#if> }
ok,到此對于該模板的編寫過程就結束了,接下來重啟下Android Studio,然后New Project一路next下去,直到這個界面,這里就是我們自定義的DebugActivity模板了
關于Android Studio模板中怎么使用文件組問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。