題外話
很久之前就了解過Google的 todo-mvp開發模式,但很長一段時間都不想用于實際項目中。主要原因就是感覺很麻煩。因為那時我用的開發模式是MVC,我理解的MVC很簡單:布局文件表示View、Activity表示Control,然后我只需新建一個類作為Model就可以了,什么臟活累活都放在Model處理,完了之后刷新布局。我的目的也很簡單:保證我的Activty整潔干凈...然而功能復雜后會讓單薄的Model變得雜亂不堪~
相比MVC,以todo-mvp為例你新建一個MVP的Activty你還要建相關的 View、Model、Presenter、Contract等等的類和接口,而且各個類、接口間的繼承和實現,眼花繚亂啊!這真的讓剛接觸的人望而止步,新增一個Activity都那么費勁了,如果一個項目下來會不會變得很臃腫?而且會額外新增巨大的工作量,種種擔憂讓我一直將MVP拒之門外,但隨著項目越來越大,功能越來越復雜 MVC出現了明顯的短板。再講下去就有點跑題了,關于MVC和MVP的對比可以參考一下淺談MVC、MVP。到這可能有孩子想說了:"別人都用MVVM了,你還用MVP,太low了!"。就像找媳婦一樣,不是哪個漂亮就去娶誰,別人也不一定看得上你,合適的才是最重要的。
入正題
于是就一直琢磨著能不能在新建一個Activity的同時生成MVP所需要的所有類和接口。網上搜索一番,發現了Android Studio中自定義模板。因為對todo-mvp不太感冒于是參考了Android簡單實用的MVP框架。
實現了以rxjava全家桶+retrofit+butterknife+eventbus+glide為技術棧的MVP模板。
因為在Create New Mvp Project的時候我會把retrofit和rxjava等用到的框架進行依賴,而且會把所有封裝的類如:retrofit工廠類、工具類等等常用的類導入進來,重點是把mvp的基類導入了進來供其他自定義模板使用。由于另外兩個模板需要用到相關的框架和自定義類,所以必須要先用Create New Mvp Project這個模板創建項目。這樣做目的主要是為了讓大家快點看到效果,同時給大家一點靈感,從而創建出屬于自己的一套模板,規范自己的代碼,提高開發效率,早點下班!
直接上效果圖(本人PS功底一般,模板的封面圖就先隨意放了)
1.新建一個項目
2.選擇模板
3.設置參數
這里要注意的是你只需要填入 Input Your Name(開發者)和File Head Name(生成所有類的名稱),其他的不用管,不要去修改Activity Name和Layout Name! 然后直接finish創建新項目。關于參數后面詳解。
4.生成MVP工程
生成MVP工程的同時會把你技術棧所用到的依賴添加進來,也包括常用的工具類、資源文件(自定義布局、動畫文件、values下的所有配置文件等等),只要你用到的基本都能添加進來。如果你是一位經常要開發新項目的猿,此時是不是想喊我baba了。不用一塊磚一塊磚般過來了,一鍵新建項目后直接干就完了!如下圖就是剛新建了工程的樣子,這是我常用的工程結構。不用像以前那樣新建項目后從其它項目把代碼復制粘貼過來了,省心!
5.新建一個新的MVP Activity或者 Fragment
注意!注意!注意!我定義的所有路徑都是基于包名下的??!新建時一定要右擊包名,然后選擇自定義的模板!這里不要選Create New Mvp Project模板了這個是新建工程的,選Create New Mvp Activity Or Fragment或者RecyclerView Activity用于生成MVP模式的Activity或Fragment
6.填寫新增模塊的參數
這里也只是修改Your Name和Component Name就可以了,然后選擇新建Activity還是Fragment 然后點擊finish即可。
7.生成新的MVP模塊
下圖是新增了一個MVP Activity模板的樣子,是不是輕輕松松就讓項目規范了起來?一鍵生成mvp模式的代碼不用做重復無用的工作,只用關心你的業務。
到這里效果基本就演示完了,因為新建項目時就依賴了相關的框架和導入了封裝好的類,所以可以直接進行網絡請求如圖:
本人同時還另外還制作了RecyclerView Activity,相信大家使用RecyclerView都會覺得有點煩,又要新建一個adapter,又要新建列表里的子布局、數據的實體類。如果是分頁列表的更煩,copy一堆接口和實現邏輯,現在可以一鍵生成是不是很爽?好了,講那么多開始講教程了,主要讓大家會自己建立一個符合自己編碼習慣的模板。我的模板只作拋磚引玉之用。
第一步找到模板文件夾
在你Android Studio安裝目錄下找到 \templates\activities這個目錄,可以看到這里面有很多自帶的模板。而我們要做的就是選一個最簡單最干凈的模板copy在當前文件夾,重命名后進行改造。如果你有其他的模板,直接拷貝到這個目錄下重啟IDE即可使用。
第二步拷貝EmptyActivity模板
然后按你們的想法把拷貝的這個模塊重命名,接下來就可以進行改造了。先介紹這幾個文件:
root:存放要導入的代碼和資源文件。
globals.xml.ftl顧名思義是定義全局參數。
recipe.xml.ftl主要負責把root里面的文件導入到項目里。
template.xml主要負責定義新建模板時所需的參數。
template_blank_activity.png是模板的封面圖片。
第三步修改模板參數文件template.xml
這里我覺得最需要注意的地方就是<parmeter>標簽里的id參數,其他地方需要用到這個<parmeter>的值只需要寫${id}即可引用,如我要用到id="componentName"的值只需要引用這個值得地方寫${componentName}即可。而且我們可以在recipe.xml和代碼、資源文件中使用。
第四步建立需要生成的資源文件
這里我用Create New Mvp Project的root講解:
我們要導入的類都放在root/src/app_package下, 這里我建議事先寫好一個可以運行的Android 模板 Demo然后再一個一個修改移植到這個目錄。第一步將要移植的文件加上.ftl,第二部打開文件修改里面的包名、類名等,不然新建出來的模板會飄紅。
如圖,我們需要用freemarker語法定義包名類名,確保生成文件的位置和你定義的是一致的。這里用到的值都是我們之前在template.xml中定義的。上面我說過,如果要在工程新建mvp模板的Activity,必需是右擊項目的包名新建??瓷蠄D第一行:package ${packageName}.activity意思就是在當前的包名下的activity文件夾內新建一個Activity,所以一定要在該包名上操作,或者自行定義,其他文件的定義也是一樣。這里要說一下引用template.xml中的值時可能要進行判斷,這時可以用
<#if 條件>
執行A
<#else>
否則執行B
</#if>
舉個例子:比如你需要根據新建模板時獲取的參數來創建不同的布局可以這樣寫:
<#if 條件>
setContentView(R.layout.activity_A);
<#else>
setContentView(R.layout.activity_B);
</#if>
在你的代碼文件或者recipe.xml.ftl中都可以使用。
還有其他很多方法大家可以去發掘,鄙人能找到的這方面資料太少。
除了添加代碼還可以添加AndroidManifest.xml,build.gradle還有res下的anim、layout、drawable、values等文件夾所以功能很是強大。
先說說比較簡單的res
像anim、drawable、layout、values這些資源問件一般直接拷貝過來就可以使用了,連.ftl后綴都不用添加在recipe.xml.ftl直接寫copy把整個文件夾都拷貝到項目里就行,但是你如果想要對里面的文件進行操作的話,那個文件就必須加上.flt不然腳本語言無法執行文件而導致報錯。
提醒一下AndroidManifest.xml,build.gradle這兩個文件,其實自己寫常用模板時很少會用到一般是新建項目的模板才會用到,因為坑很多所以有必要記錄下:在新建一個項目時,系統的公共模板文件就已經定義好這兩個文件了,如果想修改這兩個文件目前我想到的有三種方法:
(1)修改系統公共模板文件,但會影響所有的模板,難度太大風險太高不建議。
(2)直接用自己寫的AndroidManifest、build替換系統生成的文件,嘗試了很多次都是報錯,最抓狂的是他不提示你具體哪里錯了,而是談談的來一句“兄dai,報錯了”。所以無法繼續進行。
(3)用merge把內容寫入這兩個文件??梢猿晒\行,但有坑。
,AndroidManifest.xml里主要就是想添加權限,但是這里就出現了問題。如果有解決的方法的同學請賜教,本人琢磨了很久,因為找不到相關資料就不停的去嘗試。發現在AndroidManifest.xml中只添加一條權限時時沒問題的,但是添加多條權限后生成的代碼格式就亂了,還有就是build.gradle里依賴多個庫沒問題,但要想在android {}添加多行配置就出現問題了。目前解決的方法還是一行一行的添加配置。比如我要在android {}里添加
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
這里就要分兩次merge進gradle里面 ,如下圖
我要建立一個文件a內容是:
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
}
}
文件b內容是:
android {
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
}
}
通過這兩個文件我才能把把內容merge進build.gradle里面。有點復雜不推薦這樣做,我這是為了整體效果采用的極端方式。當然我最希望是把所有配置和依賴寫入build.gradle然后導進去就好了,但是均已失敗告終。原因可能很多,一是資料太少無法深入研究,基本都是靠參考系統自帶的模板 進行學習。二是可能這方面的功能不是很穩定,因為我用的是3.1.3版本的AndroidStudio,把運行完美的模板交給了使用2.1的朋友結果報錯了,里面的坑還是多哈。
上面已經準備好了生成模板的資源,現在就準備把這些資源按我們定義生成在項目里。這時就要用到recipe.xml這個文件了。
這里主要是用到了3個標簽將我們定義好的文件生成在項目里
1.merge合并,把你的資源文件的內容合并到目標文件。像AndroidManifest.xml和build.gradle只能用merge,如果想直接替換文件里面有很多問題要處理。公共模板文件里面有很多文件相互調用,而且都是用腳本語言、宏定義寫的,水平有限就只能用水平有限的方法處理了。
2.copy拷貝,顧名思義就是把你的資源文件直接拷貝到對應的路徑下了。
3.instantiate 實例,使用后加上個人理解應該是資源文件在對應的路徑下生成一個實例。
其中關于路徑我都是參考系統其他模板里面定義的,其中
${escapeXmlAttribute(manifestOut)}表示AndroidMainfest.xml所在目錄;
${escapeXmlAttribute(projectOut)}表示項目下的app文件夾路徑,和src文件夾同一層級
${escapeXmlAttribute(resOut)}表示資源文件的根目錄即res文件夾
${escapeXmlAttribute(srcOut)}表示表示項目代碼文件的根目錄
最后open標簽建新模板后AndroidStudio打開目標文件。
我剛開始寫recipe.xml的時候在想怎么在工程里新建一個目錄,然后我再把代碼文件導入到我新建的目錄。后來發現并不需要那么麻煩
<instantiate from="root/src/app_package/ModelImple.java.ftl" to="${escapeXmlAttribute(srcOut)}/implement/${componentName}ModelImple.java" />
在
to="${escapeXmlAttribute(srcOut)}/implement/${componentName}ModelImple.java"
中,implement代表路徑,只要你寫上路徑就會為你直接生成相應的文件夾。
到這基本就結束了,這里是代碼地址,只需要把模板文件放在\Android Studio\plugins\android\lib\templates\activitie下即可使用,有問題歡迎指出,也歡迎轉載,請注明出處,謝謝。