[譯] 使用自定義文件模板加快你的應用開發速度

使用自定義文件模板加快你的應用開發速度

感謝:Google Inc.,維基共享資源和 Vexelsphp

Wishfie 開發 Android 應用時,咱們常常須要編寫大量的樣板代碼以用於建立新的 Activity 和 Fragment。我會舉一個例子來講明個人意思:html

當咱們遵循 MVP 架構時,每一個新增的 Activity 或 Fragment 都須要一個 Contract 類,一個 Presenter 類,一個 Dagger 模板及 Activity 類自身,這致使咱們每次都須要編寫大量的類似代碼。前端

下面即是咱們的 Activity、Module、Contract 和 Presenter:java

public class DemoActivity extends DemoBaseActivity<DemoContract.Presenter> implements DemoContract.View {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);
    }

}
複製代碼
@Module
public abstract class DemoActivityModule {
    @Binds
    @PerActivity
    abstract DemoContract.Presenter providesPresenter(DemoPresenter demoPresenter);

    @Binds
    @PerActivity
    abstract DemoContract.View providesView(DemoActivity demoActivity);
}
複製代碼
public interface DemoContract {
    interface View extends DemoBaseContract.ActivityView {

    }

    interface Presenter extends DemoBaseContract.Presenter {

    }
}
複製代碼
public class DemoPresenter extends DemoBasePresenter<DemoContract.View> implements DemoContract.Presenter {

    @Inject
    public DemoPresenter(DemoContract.View view) {
        super(view);
    }

    @Override
    public void unSubscribe() {

    }

    @Override
    public void subscribe() {

    }
}
複製代碼

這是 android 中常見的模式,不少人可能都在使用它。這就是咱們所遇到的問題,它的解決方案來源於 Android Studio 中一個很棒的功能(自定義模板)。linux

在本文的最後,咱們將建立一個根據不一樣後綴一次建立全部必須文件的模板。那麼,讓咱們開始吧:android

Android Studio 中的模板是什麼?

Android Studio activity 建立模板ios

IntelliJ 描述以下:git

文件模板是建立新文件時要生成的默認內容規範。根據你建立的文件類型,模板提供了在該類型文件中所預期的初始化代碼和格式(根據行業標準,你的公司政策或其餘內容)。github

簡單來講,模板用於建立包含一些樣板代碼的文件。大多數狀況下,當你從預約義選項集中建立 Activity、Fragment 和 Service 等文件時,它已經爲你編寫了許多樣板代碼,這些代碼基本上都是由 Android Studio 團隊建立的一組預先編寫好的模板建立的。例如,從上圖顯示菜單建立的 empty activity 默認包含如下樣板代碼,XML 文件以及 manifest 文件的入口配置。apache

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class EmptyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
    }
}
複製代碼

你能建立什麼類型的模板?

  1. 你能夠建立 .java.xml.cpp 等類型的文件模板。

  2. 你能夠建立你本身的實時模板。若是你曾經用過 Toast 模板或用於定義 public static final intpsfi,這些被稱爲實時模板。

  3. 你能夠建立一組文件模板。好比,查看 Android Studio 如何爲 Activity 建立 .xml.java 文件,而且在 manifest 文件中添加該 activity 的詳細信息。

用什麼語言建立模板?

使用 Apache Velocity Template Language 建立這些模板。

本文章節:

  1. 咱們將首先建立一個基本文件模板,該模板將建立一個 RecyclerView Adapter 以及一個內部 ViewHolder 類,由於它是最經常使用的類之一。

  2. 咱們將建立咱們本身的實時模板。

  3. 咱們將經過編寫用於建立上述 4 個文件的模板來結束此操做,以便在咱們的應用中遵循 mvp 架構。

章節 1:

  • 右鍵單擊任何包目錄,而後選擇 New -> Edit File Templates

  • 單擊 + 按鈕建立一個新模板,並將其命名爲你想要的任何名稱。我將它命名爲 RecyclerViewAdapter。

  • 將下面的模板代碼粘貼到名稱字段下方的區域中。我會一步一步解釋代碼中發生了什麼:

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;

#parse("File Header.java")
public class ${NAME} extends RecyclerView.Adapter<${VIEWHOLDER_CLASS}> {
    private final Context context;
    private List<${ITEM_CLASS}> items;

    public ${NAME}(List<${ITEM_CLASS}> items, Context context) {
        this.items = items;
        this.context = context;
    }

    @Override
    public ${VIEWHOLDER_CLASS} onCreateViewHolder(ViewGroup parent,
                                             int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.${LAYOUT_RES_ID}, parent, false);
        return new ${VIEWHOLDER_CLASS}(v);
    }

    @Override
    public void onBindViewHolder(${VIEWHOLDER_CLASS} holder, int position) {
        ${ITEM_CLASS} item = items.get(position);
        holder.set(item);
    }

    @Override
    public int getItemCount() {
        if (items == null){
            return 0;
        }
        return items.size();
    }

    public class ${VIEWHOLDER_CLASS} extends RecyclerView.ViewHolder {

        public ${VIEWHOLDER_CLASS}(View itemView) {
            super(itemView);
        }

        public void set(${ITEM_CLASS} item) {
            //UI setting code
        }
    }
 }
複製代碼
  • 若是你快速閱讀 android studio 中代碼輸入字段下面的 Description 面板,上面的大部分代碼都很容易理解。

  • ${<VARIABLE_NAME>} 用於建立在整個模板中使用的變量,而且當你使用模板建立代碼時,系統會提示你爲它們輸入值。這還有一些預約義的變量,好比 ${PACKAGE_NAME}${DATE}等。

  • #if 指令用來檢查包名是否爲空,若是不爲空,則將名稱添加到做爲 ${PACKAGE_NAME} 變量傳遞的包語句中。

  • #parse 指令用於插入另外一個名爲 File Header.java 模板的內容,你能夠在同一窗口的 includes 選項卡下找到該模板。看起來像這樣:

  • 其他代碼使用這些變量和靜態文本,代碼和註釋來建立文件。

  • 如今右鍵單擊任何目錄,而後單擊 New,你將在那裏找到你的模板。單擊它將打開一個提示框,輸入咱們以前定義的佔位符的值。

  • 如下是咱們生成的模板:
package io.github.rajdeep1008.templatedemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

public class SchoolData extends RecyclerView.Adapter<SchoolData> {
    private final Context context;
    private List<SchoolItem> items;

    public SchoolData(List<SchoolItem> items, Context context) {
        this.items = items;
        this.context = context;
    }

    @Override
    public SchoolData onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.R.layout.item_school, parent, false);
        return new SchoolData(v);
    }

    @Override
    public void onBindViewHolder(SchoolData holder, int position) {
        SchoolItem item = items.get(position);
        holder.set(item);
    }

    @Override
    public int getItemCount() {
        if (items == null) {
            return 0;
        }
        return items.size();
    }

    public class SchoolData extends RecyclerView.ViewHolder {

        public SchoolData(View itemView) {
            super(itemView);
        }

        public void set(SchoolItem item) {
            //UI setting code
        }
    }
}
複製代碼

使用咱們的 Android Studio 模板生成文件。

章節 2:

  • 這個章節與咱們爲 mvp 源文件建立模板的最終目的沒什麼關係,但知道 Android Studio 爲咱們提供的每一個選項是有好處的。

  • 實時模板是你在代碼中快速獲取代碼段的快捷方式。你還能夠添加參數來快速標記它們。

在 Android Studio 中播放實時模板。

  • 對於 mac 用戶,導航到 Android Studio -> Preferences -> Editor -> Live Templates,在這裏你將看到一個包含已有實時模板的列表框,好比 fbc 用於 findViewById 映射,foreach 用於建立 loop 等。

  • 如今點擊 Android -> + ->LiveTemplate,你能夠選擇添加縮寫來使用模板,說明模板的功能以及模板的模板文本。

  • 如今點擊 Define 並選擇彈框中的 XML 選項來選擇模板可用的文件類型。

Android Studio 中實時模版建立嚮導

  • 單擊肯定保存並開始使用它。打開 XML 佈局文件並開始輸入 rv 並按 Tab 以適用新建立的模板。

咱們新建立的實時模板

章節 3:

Pheww!咱們已經介紹了不少東西,如今是時候開始建立咱們的 mvp 模板了。咱們須要建立一個 Activity、DaggerModule、Contract 和 Presenter。前綴將做爲用戶輸入,剩下的將採用本文開頭所述的格式。

  • 導航到你的 Windows/Linux/Mac 文件系統中的 Android Studio 目錄,而後轉到 plugins -> android -> lib -> templates -> other,用你但願在菜單中看到的名稱建立一個空目錄,我將其命名爲 MVP Template。

  • 在 mac 中,目錄的位置應該爲 /Applications/Android/Studio.app/Contents/plugins/android/lib/templates/other/,對於 windows 或 linux,你能夠在 {ANDROID_STUDIO_LOCATION}/plugins/android/lib/templates/other/ 中找到它。

  • 確保檢查模板中的 activities 目錄,看看如何模板建立 EmptyActivity、BasicActivity 以及其餘文件,這將有助於編寫本身的模板。

  • 如今,在新建立的 MVP Template 目錄中,建立 template.xml、recipe.xml.ftlglobals.xml.ftl。而且建立一個名爲 root 的目錄,它將保存咱們建立的實際模板文件。我將逐一解釋每一個文件的做用:

  1. template.xml — 它用來處理屏幕配置的 UI 部分。 它定義了用戶在使用模板建立文件時看到的用戶輸入字段、複選框和下拉列表等。

  2. recipe.xml.ftl — 這是使用的文件,你的根目錄中的模板將轉換爲 Android Studio 中真實的 java 文件。它包含有關要建立哪些文件以及從哪些模板建立等信息。

  3. globals.xml.ftl — 這包含全部全局變量。在這裏爲 src 和 res 定義目錄路徑是一個很好的作法。

  • 在 template.xml 文件中,粘貼如下代碼:
<template format="4" revision="1" name="MVP Template Activity" description="Creates a new MVP classes - Presenter, View, Contract and Dagger Module.">

    <category value="Other"/>

    <parameter id="className" name="Functionality Name" type="string" constraints="class|unique|nonempty" default="MvpDemo" help="The name of the functionality that requires MVP views"/>

    <globals file="globals.xml.ftl" />
    <execute file="recipe.xml.ftl" />

</template>
複製代碼

template.xml 描述了應該從用戶那裏得到的參數:

  1. id 是該元素的惟一 id。
  2. name 只是向用戶顯示的提示(就像在 EditText 中的提示同樣)。
  3. type 定義用戶應該顯示文本輸入仍是下拉控件中的枚舉值,或在布爾值的狀況下顯示覆選框。
  4. default 用戶輸入爲空時的默認值。
  5. globalsexecute 屬性連接咱們的全局變量和配置文件。
  • 在 recipe.xml.ftl 文件中,粘貼如下代碼:
<?xml version="1.0"?>
<recipe>

    <instantiate from="src/app_package/Contract.java.ftl" to="${escapeXmlAttribute(srcOut)}/${className}Contract.java" />
    <instantiate from="src/app_package/Activity.java.ftl" to="${escapeXmlAttribute(srcOut)}/${className}Activity.java" />
    <instantiate from="src/app_package/Presenter.java.ftl" to="${escapeXmlAttribute(srcOut)}/${className}Presenter.java" />
    <instantiate from="src/app_package/ActivityModule.java.ftl" to="${escapeXmlAttribute(srcOut)}/${className}ActivityModule.java" />


    <open file="${srcOut}/${className}Presenter.java"/>
    <open file="${srcOut}/${className}Contract.java"/>
    <open file="${srcOut}/${className}Activity.java"/>
    <open file="${srcOut}/${className}ActivityModule.java"/>
</recipe>
複製代碼

recipe.xml.ftl 定義從哪一個模板建立哪些文件以及建立後打開哪些文件。它還能夠將代碼從咱們的模板複製到 manifest.xml 或 string.xml 等文件中。請務必查看用於建立 activities 的默認模板示例。

className 變量是咱們從用戶那裏獲取的輸入的 id,其代碼用 template.xml 編寫,srcOut 在 globals.xml.ftl 中定義。文件的其餘部分具備很好的自我解釋能力。

  • 在 globals.xml.ftl 中:
<?xml version="1.0"?>
<globals>
 <global id="resOut" value="${resDir}" />
 <global id="srcOut" value="${srcDir}/${slashedPackageName(packageName)}" />
</globals>
複製代碼
  • 如今,在根目錄中,建立 src/app_package/ 目錄並將如下四個文件複製到該目錄中:
package ${packageName};

public class ${className}Activity extends DemoBaseActivity<${className}Contract.Presenter> implements ${className}Contract.View {

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);
    }

}
複製代碼
package ${packageName};

@Module
public abstract class ${className}ActivityModule {
    @Binds
    @PerActivity
    abstract ${className}Contract.Presenter providesPresenter(${className}Presenter presenter);

    @Binds
    @PerActivity
    abstract ${className}Contract.View providesView(${className}Activity activity);
}
複製代碼
package ${packageName};

public interface ${className}Contract{

    interface View extends DemoBaseContract.ActivityView {

    }

    interface Presenter extends DemoBaseContract.Presenter {

    }
}
複製代碼
package ${packageName};

public class ${className}Presenter extends DemoBasePresenter<${className}Contract.View> implements ${className}Contract.Presenter {

    @Inject
    public ${className}Presenter(${className}Contract.View view){
        super(view);
    }

    @Override
    public void subscribe() {

    }

    @Override
    public void unSubscribe() {

    }
}
複製代碼

這些文件包含將徹底轉換爲 java 或 xml 代碼的模板,參數將被實際值替換。

咱們終於完成了全部步驟。只須要重啓 Android Studio 便可啓用此模板,並顯示在菜單中。

咱們新建立的 MVP 模板

若是使用得當,Android Studio 模板是加快應用開發速度的強大功能。這些模板能夠分佈在整個 Android 團隊中,以便簡化樣板代碼的建立。

以上即是本文的全部內容。若是你喜歡這篇文章並發現它有用,請不要忘記點贊並與其餘 Android 開發者分享它。Happy coding 💗。

順便說一句我開通了每週簡報 thedevweekly我將經過網站、移動設備和系統上精心挑選文章,並在有關新技術學習及一些大科技公司內部學習文章之間取得平衡。

所以,不管你是初學者仍是專家,若是你正在尋找精心策劃的科技文章的每週摘要,請在 這裏 註冊 .


參考資料:

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索