一個(gè)大型Android應(yīng)用通常分為多個(gè)模塊浸须,每個(gè)模塊移怯,尤其是與視圖相關(guān)的模塊始赎,通常需要Context進(jìn)行構(gòu)建和橙,比如視圖的創(chuàng)建需要傳遞Context。
每個(gè)模塊的對(duì)外需要一個(gè)接口調(diào)用來啟動(dòng)該模塊功能造垛。良好的模塊設(shè)計(jì)通常采用MVC或擴(kuò)展模型魔招,也就是模塊包含Model、View和Controller五辽。
Controller兼任兩個(gè)角色:一個(gè)是對(duì)外提供調(diào)用接口办斑,我們稱之為Manager角色;另一個(gè)是對(duì)外調(diào)用杆逗,我們稱之為Bridger角色乡翅。如果Bridger角色任務(wù)較輕,我們通常把它并入到Manager角色中罪郊,統(tǒng)稱為Manager峦朗,以之作為模塊的Controller。
在整個(gè)應(yīng)用中排龄,頻繁使用的模塊Manager通常是單例。我們知道單例的標(biāo)準(zhǔn)寫法:getInstance()翎朱,不傳遞參數(shù)橄维。那么問題來了:模塊需要的Context如何傳進(jìn)來?我們可能會(huì)這么做:給getInstance加一個(gè)Context參數(shù)拴曲,Context是傳進(jìn)來争舞,可以想象代碼會(huì)多么地不優(yōu)雅。我們也可能這樣做澈灼,在Manager的調(diào)用接口中增加Context參數(shù)竞川,這樣做的壞處:一是如果Manager創(chuàng)建的時(shí)候就需要Context就麻煩了店溢;另一個(gè),每個(gè)接口都加上一個(gè)額外的Context也顯得不太優(yōu)雅委乌。
Context容器模型可以很好地解決模塊Context傳遞的問題床牧。
Context容器模型提供一個(gè)ContextContainer,ContextContainer中包含一個(gè)靜態(tài)protected的Context變量和一個(gè)靜態(tài)protected的Activity變量:
protected static Context sContext;
protected static Activity sActivity;
并提供一個(gè)靜態(tài)初始化方法:
public void static init(Activity activity) {
sContext = sActivity = activity;
}
提供一個(gè)靜態(tài)釋放方法:
protected static void recycleContext() {
if (!matchToken()) {
return ;
}
sContext = null;
sActivity = null;
}
初始化方法在應(yīng)用Activity創(chuàng)建之初調(diào)用遭贸,將當(dāng)前Context保存在ContextContainer中戈咳;釋放方法在Activity退出時(shí)調(diào)用。釋放方法中有一個(gè)檢查邏輯(matchToken)壕吹,這個(gè)檢查是判斷當(dāng)前Context是否為初始化時(shí)的Context著蛙,保證釋放的是初始化后不再使用的Context,否則說明已經(jīng)有其他Activity已經(jīng)啟動(dòng)耳贬,不用再對(duì)Context進(jìn)行釋放踏堡。
有了ContextContainer,模塊Manager可以直接繼承ContextContainer咒劲,即可直接使用上下文變量sContext和sActivity顷蟆。考慮到j(luò)ava的單繼承缎患,有人可能會(huì)懷疑這樣做會(huì)不會(huì)妨礙Manager繼承其他類慕的?通常來講,模塊Manager通常是獨(dú)立的挤渔,不依賴于系統(tǒng)里控件肮街,因此它通常不會(huì)繼承繼承其他類,如果要繼承判导,那也是繼承一個(gè)ManagerBase類嫉父,而ManagerBase類也可以繼承ContextContainer。所以眼刃,無論是Manager直接繼承ContextContainer绕辖,還是間接繼承于ContextContainer,在Manager中都可以自由使用Context擂红。
Context容器模型除了為模塊提供Context的自由訪問功能仪际,還有一個(gè)好處:整個(gè)應(yīng)用對(duì)Context的引用減少,所有模塊Manager都不持有Context的引用昵骤,因此除了直接引用Context的組件成員(View組件)外树碱,Manager不需要關(guān)心Context的變化,從而減少了對(duì)Context的依賴变秦。
這一點(diǎn)對(duì)于Activity的重入復(fù)用是非常有幫助的成榜。簡(jiǎn)單來說,當(dāng)Activity finish退出后蹦玫,如果不釋放Manager實(shí)例及其Model赎婚,那么在Activity再次啟動(dòng)時(shí)栅哀,Manager和Model不需要重新初始化炕淮,直接復(fù)用即可。這對(duì)于提升熱啟動(dòng)速度是非常有幫助的,尤其對(duì)于數(shù)據(jù)加載比較耗時(shí)的模塊豪嚎。重入復(fù)用模型設(shè)計(jì)會(huì)采用該方式鲫咽。
Context容器模型缺脉,不依賴于應(yīng)用上真,因此可以在任何應(yīng)用中直接使用。
在Context容器模型的基礎(chǔ)上绢馍,可以進(jìn)行應(yīng)用拓展向瓷。比如應(yīng)用中所有的Activity都繼承自BasicActivity,那么可以定義一個(gè)BasicContainer舰涌,繼承自ContextContainer猖任,同時(shí)保存一個(gè)靜態(tài)protected的BasicActivity變量,這樣BasicContainer既提供了通用Context的方法瓷耙,又提供了BasicActivity的訪問方法朱躺。對(duì)于需要進(jìn)行BasicActivity的模塊,Manager繼承BasicContainer即可搁痛。
Context容器模型就介紹到這里长搀,總結(jié)一下:
Context容器模型提供容器類ContextContainer,保存Context變量鸡典。
容器在Activity創(chuàng)建之初進(jìn)行初始化源请。
模塊Manager繼承ContextContainer,方便使用Context變量彻况。
Context容器模型減少了這個(gè)應(yīng)用對(duì)于Context的引用和依賴谁尸,基于此可以實(shí)現(xiàn)應(yīng)用的重入復(fù)用。