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

淚已無痕發表於2018-12-24

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

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

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

Wishfie 開發 Android 應用時,我們經常需要編寫大量的樣板程式碼以用於建立新的 Activity 和 Fragment。我會舉一個例子來說明我的意思:

當我們遵循 MVP 架構時,每個新增的 Activity 或 Fragment 都需要一個 Contract 類,一個 Presenter 類,一個 Dagger 模板及 Activity 類自身,這導致我們每次都需要編寫大量的相似程式碼。

下面便是我們的 Activity、Module、Contract 和 Presenter:

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 中一個很棒的功能(自定義模板)。

在本文的最後,我們將建立一個根據不同字尾一次建立所有必須檔案的模板。那麼,讓我們開始吧:

Android Studio 中的模板是什麼?

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

Android Studio activity 建立模板

IntelliJ 描述如下:

檔案模板是建立新檔案時要生成的預設內容規範。根據你建立的檔案型別,模板提供了在該型別檔案中所預期的初始化程式碼和格式(根據行業標準,你的公司政策或其他內容)。

簡單來說,模板用於建立包含一些樣板程式碼的檔案。大多數情況下,當你從預定義選項集中建立 Activity、Fragment 和 Service 等檔案時,它已經為你編寫了許多樣板程式碼,這些程式碼基本上都是由 Android Studio 團隊建立的一組預先編寫好的模板建立的。例如,從上圖顯示選單建立的 empty activity 預設包含以下樣板程式碼,XML 檔案以及 manifest 檔案的入口配置。

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前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章