起因
? 最近一直在做Android框架方面的工作,先是把原來的網(wǎng)絡(luò)框架由Netroid改為了Retrofit+Rxjava凌盯,然后在這次修改的基礎(chǔ)上付枫,有做了大量的基礎(chǔ)的Activity和Fragment的封裝烹玉,以及對(duì)應(yīng)的MVP的架構(gòu)封裝驰怎,也是經(jīng)過多次修改調(diào)整后,基本成型了二打,隨后單開一篇文章介紹這個(gè)Android架構(gòu)县忌,這個(gè)架構(gòu)適合小項(xiàng)目,小團(tuán)隊(duì)使用,也是根據(jù)網(wǎng)上的大牛提供的思路症杏,自己實(shí)踐來的装获,經(jīng)過幾次進(jìn)化后,應(yīng)付中小項(xiàng)目應(yīng)該是綽綽有余了厉颤。
? 中小型項(xiàng)目框架涵蓋的關(guān)鍵字:MVP穴豫、Retrofit、RXAndroid逼友、RxAndroidLifeCycle精肃、EventBus、LitePal帜乞、CommonUtils(涵蓋非常全面的工具類庫)等司抱。
有句話說的好:既得隴,復(fù)望蜀黎烈。
? 在中小型項(xiàng)目的框架成功后习柠,我覺得不如就此機(jī)會(huì)把組件化的架構(gòu)一并實(shí)現(xiàn),于是就開始學(xué)習(xí)組件化的架構(gòu)組織照棋,一步一步的把自己的項(xiàng)目架構(gòu)慢慢的轉(zhuǎn)成了組件化的開發(fā)资溃,不過目前還沒有完成,有幾個(gè)問題需要處理:
- 引入路由組件
- 封裝常用的自定義View
- 封裝業(yè)務(wù)組件:通用Dialog,通用RecycleView必怜、通用進(jìn)度條等肉拓,這個(gè)就很隨意了,主要還是看開發(fā)者自己的主觀意愿梳庆。
? 在初步的完成了封裝后暖途,發(fā)現(xiàn)了一個(gè)問題,就是我把原來在單一項(xiàng)目框架下的源碼轉(zhuǎn)移到了組件化框架下的子業(yè)務(wù)框架下膏执,說白了就是在組件化開啟的前提下驻售,把源碼從App轉(zhuǎn)移到了Library下,從理論上來說更米,應(yīng)該不會(huì)有什么問題欺栗,但是歷史實(shí)踐告訴我們,理論往往是靠不住的征峦,在轉(zhuǎn)移的過程中迟几,我就遇到了ButterKnife造成的問題。
問題
下面我們來看一下具體的問題:
如果你強(qiáng)制編譯栏笆,Build控制臺(tái)就會(huì)很貼心的用中文再告訴你一次:
元素值必須為常量表達(dá)式类腮?怎么就不是常量了?蛉加!我們知道R.id.XX其實(shí)就是引入了R文件中的一個(gè)靜態(tài)常量蚜枢,所謂的靜態(tài)常量其實(shí)就是static final的中文說法缸逃,于是我點(diǎn)開了R文件:
好吧,沒有final.......正常的Application中的R文件應(yīng)該是這樣的:
為什么缺少了final關(guān)鍵字呢厂抽?原因其實(shí)谷歌已經(jīng)給出了:
從ADT14開始Library中的R文件才從靜態(tài)常量變?yōu)榉浅A?因?yàn)槿绻诙鄠€(gè)Library中可能出現(xiàn)id沖突的問題.在ADT14以前則采用的是將所有的資源文件和相關(guān)的代碼重新隨著主項(xiàng)目一起編譯,導(dǎo)致編譯速度過慢.因此,從ADT14開始就變成了非常量的id了需频。
雖然這個(gè)改動(dòng)的出發(fā)點(diǎn)是好的,但是隨著組件化越來越普及筷凤,業(yè)務(wù)組件放在library的情況會(huì)越來越多昭殉,ButterKnife需要在Library中使用的情況也越來越多,所以藐守,JakeWharton大神終于在大家的呼喚下饲化,讓ButterKnife支持Library了。
解決
官方的解決方案:
第一步
在項(xiàng)目的build.gradle中的dependencies中加入:classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-rc1'
第二步
在業(yè)務(wù)子Library的Build.gradle中加入:apply plugin: 'com.jakewharton.butterknife'
這里要注意:
if (isModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
apply plugin: 'com.jakewharton.butterknife'
不論你是否開啟組件化吗伤,都要把這個(gè)插件加入進(jìn)去吃靠。
第三步
這里要注意了,敲黑板足淆!
如果你的ButterKnife的依賴是集成在本業(yè)務(wù)Library中的巢块,那你就不用管我下面說的話了,如果不是巧号,一定要看仔細(xì)族奢!
我的ButterKnife就不是封裝在本業(yè)務(wù)的Library中的,而是在其底層的一個(gè)名為BaseLib的Library中引入的丹鸿,該Library主要是提供BaseActivity和BaseFragment等基礎(chǔ)組件的越走,在該Library中引入也是為了合理的處理所有ButterKnife的解綁操作,那么這時(shí)靠欢,如果你要在你的業(yè)務(wù)Library中使用ButterKnife廊敌,你不必重復(fù)引入ButterKnife的依賴,而是在業(yè)務(wù)Library中加入:
dependencies {
api project(':BaseLib')
//這里要將ButterKnife的注解加入主項(xiàng)目中去门怪,因?yàn)樽禹?xiàng)目無法通過api引入
annotationProcessor "com.jakewharton:butterknife-compiler:$butterknife_version"
}
否則就會(huì)出現(xiàn)一個(gè)問題骡澈,那就是你的項(xiàng)目在編譯時(shí)不會(huì)報(bào)錯(cuò),但是在運(yùn)行時(shí)就會(huì)報(bào)空指針的錯(cuò)誤:
2018-10-26 16:33:50.166 15872-15872/? W/System.err: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxx.read/com.xxx.read.ReadActivityMainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setVisibility(int)' on a null object reference
2018-10-26 16:33:50.167 15872-15872/? W/System.err: at com.dhcc.commonutils.BarUtils.setStatusBarAlpha(BarUtils.java:294)
2018-10-26 16:33:50.167 15872-15872/? W/System.err: at com.dhcc.commonutils.BarUtils.setStatusBarAlpha4Drawer(BarUtils.java:385)
2018-10-26 16:33:50.167 15872-15872/? W/System.err: at com.dhcc.read.ReadActivityMainActivity.initView(ReadActivityMainActivity.java:95)
2018-10-26 16:33:50.167 15872-15872/? W/System.err: at com.dhcc.baseLib.base.activity.BaseActivity.onCreate(BaseActivity.java:51)
2018-10-26 16:33:50.167 15872-15872/? W/System.err: at com.dhcc.read.ReadActivityMainActivity.onCreate(ReadActivityMainActivity.java:228)
這個(gè)問題比較特殊掷空,并不是所有人都會(huì)遇到肋殴,如果你遇到了,記得按照我這樣處理坦弟,就可以了护锤。
第四步
把業(yè)務(wù)Library項(xiàng)目中的所有關(guān)于ButterKnife的R引用,改為R2引用即可酿傍。
如:
@BindView(R2.id.toolbar)
Toolbar toolbar;
@BindView(R2.id.fake_status_bar)
View fakeStatusBar;
@BindView(R2.id.textView)
TextView textView;
這里注意一下烙懦,并不是所有的R文件都改成R2,如果是R.layout這類R引用就不要更改,保持原狀即可拧粪,否則會(huì)在運(yùn)行時(shí)報(bào)出找不到View的指定ID的錯(cuò)誤修陡。
如:
/**
* 綁定布局
*
* @return 布局 Id
*/
@Override
public int bindLayout() {
return R.layout.read_activity_main;
}
總結(jié)
任何一個(gè)架構(gòu)的形成都有門檻,有坑可霎,有知識(shí)魄鸦,有趣,我不愿意做那種被安排的程序員癣朗,所以拾因,這些坑其實(shí)都是我的樂趣所在,今天拿出我的趟坑經(jīng)驗(yàn)分享給大家旷余,是希望看到的朋友可以走的比我更遠(yuǎn)绢记。
謝謝你的閱讀。