本文轉(zhuǎn)自Mr.Simple的博客,如侵刪
前言
在開發(fā)過程中貌笨,網(wǎng)絡(luò)是我們很重要的一部分耳奕,因此我們就以網(wǎng)絡(luò)框架或者說網(wǎng)絡(luò)模塊開始衅斩。在這個(gè)框架開發(fā)過程中盆顾,我會(huì)整理開發(fā)思路、以及遇到一些設(shè)計(jì)問題時(shí)會(huì)有怎么樣的考慮畏梆、解決方案您宪,當(dāng)然這只是我個(gè)人的觀點(diǎn),大家也可以有自己的實(shí)現(xiàn)奠涌。除了網(wǎng)絡(luò)框架宪巨,后續(xù)的系列還想更新ImageLoader框架、ORM框架溜畅,如果有時(shí)間也會(huì)增加動(dòng)畫框架和微博開發(fā)的系列文章捏卓。當(dāng)然這些框架只是一些簡(jiǎn)單的框架基礎(chǔ),本人水平慈格、時(shí)間有限怠晴,而且已經(jīng)有現(xiàn)成贿肩、成熟的很多框架,我們?cè)谶@里只是以重復(fù)造輪子的態(tài)度去學(xué)習(xí)輪子構(gòu)建過程龄寞,從而達(dá)到能夠造輪子的地步汰规。至于很多細(xì)節(jié)的問題,我們這里就補(bǔ)過多討論了物邑,如果有興趣溜哮,各位可以自行研究。
最后色解,我們暫且把這個(gè)框架命名為Simple_Net_Framework茂嗓,下面我們一起進(jìn)入主題吧。
基本結(jié)構(gòu)
SimpleNet框架的基本結(jié)構(gòu)類似于Volley,包括一些命名上也有跟Volley一致科阎。它主要分為四個(gè)部分述吸,最上面的部分為Request,即各種請(qǐng)求類型锣笨。例如返回的數(shù)據(jù)類型為json的對(duì)應(yīng)為JsonRequest蝌矛,返回?cái)?shù)據(jù)字符串的為StringRequest,如果需要上傳文件错英,那么你需要使用MultipartRequest入撒,該請(qǐng)求只支持小文件的上傳,如果上傳的文件過大則會(huì)產(chǎn)生OOM椭岩。
第二部分為消息隊(duì)列茅逮,消息隊(duì)列維護(hù)了提交給網(wǎng)絡(luò)框架的請(qǐng)求列表,并且根據(jù)相應(yīng)的規(guī)則進(jìn)行排序判哥。默認(rèn)情況下更具優(yōu)先級(jí)和進(jìn)入隊(duì)列的順序來執(zhí)行献雅,該隊(duì)列使用的是線程安全的PriorityBlockingQueue<E>,因?yàn)槲覀兊年?duì)列會(huì)被并發(fā)的訪問塌计,因此需要保證訪問的原子性挺身。
第三部分是Executor,也就是網(wǎng)絡(luò)的執(zhí)行者夺荒。該Executor繼承自Thread瞒渠,在run方法中循環(huán)訪問第二部分的請(qǐng)求隊(duì)列,請(qǐng)求完成之后將結(jié)果投遞給UI線程技扼。為了更好的控制請(qǐng)求隊(duì)列伍玖,例如請(qǐng)求排序、取消等操作剿吻,這里我們并沒有使用線程池來操作窍箍,而是自行管理隊(duì)列和Thread的形式,這樣整個(gè)結(jié)構(gòu)也變得更為靈活。
第四部分則是Response投遞類椰棘,在第三部分的Executor中執(zhí)行網(wǎng)絡(luò)請(qǐng)求纺棺,Executor是Thread,但是我們并不能在主線程中更新UI邪狞,因此我們使用ResponseDelivery來封裝Response的投遞祷蝌,保證Response執(zhí)行在UI線程。
每個(gè)部分職責(zé)都相對(duì)單一帆卓,這樣便于日后的升級(jí)和維護(hù)巨朦。
框架分析
圖1中看起來有點(diǎn)像是分層架構(gòu),其實(shí)不是剑令,這個(gè)圖更多的是表達(dá)了它的邏輯順序糊啡,而不是結(jié)構(gòu)。而在我們的應(yīng)用開發(fā)中吁津,分層架構(gòu)是一個(gè)重要的手段棚蓄,如圖2所示。
但在開發(fā)過程中碍脏,我們往往會(huì)把UI和業(yè)務(wù)層耦合起來梭依,因?yàn)樗鼈兊年P(guān)系太密切了,分解起來并不是那么容易潮酒。高手能夠把復(fù)雜的事情簡(jiǎn)單化睛挚,而分解就是簡(jiǎn)單化的重要手段,分解這個(gè)過程在開發(fā)過程中我們成為重構(gòu)急黎。但是如何分離UI和業(yè)務(wù)層也是本人最近想學(xué)習(xí)的,如果各位有好的解決方案侧到,還希望多多指教勃教。
那么我們就引入了一個(gè)分層概念,為了便于理解你也可以按照如圖1的結(jié)構(gòu)來加深理解匠抗。那么分層有什么優(yōu)缺點(diǎn)呢故源?
優(yōu)點(diǎn):
1.復(fù)雜問題分解簡(jiǎn)單化,每一層負(fù)責(zé)自己的實(shí)現(xiàn)汞贸,并向外提供服務(wù)绳军;
2.職責(zé)分離,復(fù)雜的系統(tǒng)都有很多人員進(jìn)行開發(fā)矢腻,這些功能開發(fā)的管理和集成是個(gè)很嚴(yán)重的問題门驾,分層設(shè)計(jì)實(shí)現(xiàn)之后,每層只需定義好自己的對(duì)外接口多柑,其他依賴層服務(wù)的就可以進(jìn)行開發(fā)奶是;
3.每一層對(duì)其他層都是獨(dú)立的,對(duì)外隱藏實(shí)現(xiàn)細(xì)節(jié),上層無需知道下層的細(xì)節(jié)聂沙,只需調(diào)用接口即可秆麸;
4.有利于標(biāo)準(zhǔn)化。
缺點(diǎn):
1.分層之后對(duì)于領(lǐng)域業(yè)務(wù)的修改有可能需要修改很多層及汉;
2.過多的層次影響性能沮趣。
如上所說,我們的Simple_Net_Framework并不是分層的坷随,而是簡(jiǎn)單的模塊化兔毒,但是理論基礎(chǔ)都是類似的,依賴于抽象而不依賴于實(shí)現(xiàn)甸箱、單一職責(zé)......這里引入分層的概念育叁,這是便于理解,同時(shí)也是希望大家在開發(fā)過程中能夠盡量保證模塊的內(nèi)聚性芍殖、耦合性豪嗽。
再看Simple_Net_Framework,Request是一個(gè)抽象的泛型類豌骏,泛型類型就是返回的Response類型龟梦,例如StringRequest就是繼承自Request<String>。第二部分的RequestQueue依賴于Request窃躲,Request是抽象的计贰,因此任何Request的子類都可以傳遞到請(qǐng)求隊(duì)列中來,它依賴的是抽象Request蒂窒,而不是具體的某個(gè)實(shí)現(xiàn)躁倒,因此保證了可擴(kuò)展性。你可以自己實(shí)現(xiàn)自己所需的Request洒琢,例如大文件的上傳Request秧秉。同理,第三部分的NetworkExecutor也只是依賴于Request抽象衰抑,但這里又引入了一個(gè)類型HttpStack象迎,這個(gè)網(wǎng)絡(luò)請(qǐng)求的真正執(zhí)行者,有HttpClientStack和HttpUrlConnStack呛踊,兩者分別為Apache的HttpClient和java的HttpURLConnection砾淌,關(guān)于這兩者的區(qū)別請(qǐng)參考:Android訪問網(wǎng)絡(luò),使用HttpURLConnection還是HttpClient谭网?汪厨。HttpStack也是一個(gè)抽象,具體使用HttpClient還是HttpURLConnection則由運(yùn)行系統(tǒng)版本來定蜻底,HttpStackFactory會(huì)根據(jù)系統(tǒng)版本給框架返回對(duì)應(yīng)的HttpStack骄崩。最后的ResponseDelivery比較簡(jiǎn)單了聘鳞,只是通過Handler將結(jié)果投遞給UI線程執(zhí)行,也就是執(zhí)行RequestListener的onComplete方法要拂,此時(shí)網(wǎng)絡(luò)執(zhí)行完成抠璃,用戶即可在該方法中更新UI或者相關(guān)的其他的操作。
下面我們?cè)倏纯碨impleNet的工程結(jié)構(gòu)脱惰,如圖3所示搏嗡。
這就是Simple_Net_Framework框架的基本結(jié)構(gòu)了
GitHub