Android 搭建MVP+Retrofit+RxJava網(wǎng)絡(luò)請求框架(一)

之前公司的項(xiàng)目用到了MVP+Retrofit+RxJava的框架進(jìn)行網(wǎng)絡(luò)請求宏蛉,所以今天特此寫一篇文章以做總結(jié)肯污。相信很多人都聽說過MVP颁独、Retrofit彩届、以及RxJava,有的人已經(jīng)開始用了奖唯,有的人可能還不知道這是什么惨缆,以及到底怎么用。不過沒關(guān)系丰捷,接下來我將為你一一揭開他們的神秘面紗坯墨,然后利用這三個(gè)家伙搭建一個(gè)網(wǎng)絡(luò)請求框架

1.什么是MVP?

MVP(Model View Presenter)其實(shí)就是一種項(xiàng)目的整體框架病往,能讓你的代碼變得更加簡潔捣染,說起框架大家可能還會想到MVC、MVVM停巷。由于篇幅原因耍攘,這里我們先不講MVVM,先來看一下MVC畔勤。其實(shí)Android本身就采用的是MVC(Model View Controllor)模式蕾各、其中Model指的是數(shù)據(jù)邏輯和實(shí)體模型;View指的是布局文件庆揪、Controllor指的是Activity式曲。對于很多Android初學(xué)者可能會有這樣的經(jīng)歷,寫代碼的時(shí)候缸榛,不管三七二十一都往Activity中寫吝羞,當(dāng)然我當(dāng)初也是這么干的,根本就沒有什么框架的概念内颗,只要能實(shí)現(xiàn)某一個(gè)功能就很開心了钧排,沒有管這么多。當(dāng)然項(xiàng)目比較小還好均澳,一旦項(xiàng)目比較大恨溜,你會發(fā)現(xiàn),Activity所承擔(dān)的任務(wù)其實(shí)是很重的负懦,它既要負(fù)責(zé)頁面的展示和交互筒捺,還得負(fù)責(zé)數(shù)據(jù)的請求和業(yè)務(wù)邏輯之類的工作,相當(dāng)于既要打理家庭纸厉,又要教育自己調(diào)皮的孩子,真是又當(dāng)?shù)之?dāng)媽五嫂。颗品。肯尺。那該怎么辦呢?這時(shí)候Presenter這個(gè)繼父來到了這個(gè)家庭躯枢。Presenter對Activity說则吟,我來了,以后你就別這么辛苦了锄蹂,你就好好打理好View這個(gè)家氓仲,我專門來負(fù)責(zé)教育Model這孩子,有什么情況我會向你反映的得糜。這時(shí)Activity流下了幸福的眼淚敬扛,從此,Model朝抖、View(Activity)啥箭、Presenter一家三口過上了幸福的生活。治宣。急侥。好了磕個(gè)藥繼續(xù),由于Presenter(我們自己建的類)的出現(xiàn)侮邀,可以使View(Activity)不用直接和Model打交道坏怪,View(Activity)只用負(fù)責(zé)頁面的顯示和交互,剩下的和Model交互的事情都交給Presenter做绊茧,比如一些網(wǎng)絡(luò)請求铝宵、數(shù)據(jù)的獲取等,當(dāng)Presenter獲取到數(shù)據(jù)后再交給View(Activity)進(jìn)行展示按傅,這樣捉超,Activity的任務(wù)就大大減小了。這便是MVP(Model 還是指的數(shù)據(jù)邏輯和實(shí)體模型唯绍,View指的是Activity拼岳,P就是Presenter)框架的工作方式。

2.什么是Retrofit况芒?

接下來我們看一下什么是Retrofit惜纸。在官網(wǎng)對Retrofit的描述是這樣的

A type-safe HTTP client for Android and Java說人話就是“一個(gè)類型安全的用于Android和Java網(wǎng)絡(luò)請求的客戶端”,其實(shí)就是一個(gè)封裝好的網(wǎng)絡(luò)請求庫绝骚。接下來就來看一下這個(gè)庫該怎么用耐版。首先我在網(wǎng)上找了一個(gè)API接口用于測試:https://api.douban.com/v2/book/search?q=金瓶梅&tag=&start=0&count=1這是一個(gè)用于查詢一本書詳細(xì)信息的一個(gè)請求接口。如果直接用瀏覽器打開的話會返回以下內(nèi)容:

瀏覽器中返回內(nèi)容

接下來我們來看看如何用Retrofit將上面的請求下來压汪。為了在Android Studio中添加Retrofit庫粪牲,我們需要添加如下依賴:

compile 'com.squareup.retrofit2:retrofit:2.1.0'

好了,添加完該庫止剖,我們再來看看如何使用腺阳,首先我們來建一個(gè)實(shí)體類Book落君,用于裝網(wǎng)絡(luò)請求后返回的數(shù)據(jù)。這里順帶說一下亭引,有的人建一個(gè)實(shí)體類時(shí)可能會根據(jù)瀏覽器中返回中的數(shù)據(jù)一行一行敲绎速,其實(shí)這樣非常麻煩,這里教大家一個(gè)簡單的方法焙蚓,瞬間生成一個(gè)實(shí)體類纹冤。沒錯(cuò)有的人可能用過,我們需要一個(gè)插件GsonFormat购公。它的使用也很簡單萌京,首先需要在Android Studio中下載,點(diǎn)擊左上角菜單欄中的File,然后點(diǎn)擊Settings君丁,在彈窗中選擇Plugins,然后點(diǎn)擊下方的Browse repositories...

然后在新打開的窗口中搜索GsonFormat枫夺,點(diǎn)擊右側(cè)綠色按鈕就可以下載安裝了,安裝完需要重啟下studio绘闷,就可以用了橡庞。

它的用法也很簡單,比如你先建立一個(gè)新的空類取名Book印蔗,然后在里面按Alt+insert,會有個(gè)小彈窗選擇GsonFormat,之后在彈出的編輯框中拷入在瀏覽器中請求下來的那一坨東西扒最,然后一直點(diǎn)ok就會自動(dòng)生成字段,以及set和get方法华嘹,一會兒我們用Retrofit請求下來的數(shù)據(jù)都會保存在這個(gè)實(shí)體類中吧趣,還是挺方便的。最后我們里面添加一個(gè)toString()方法耙厚,用于后面顯示方便强挫。

接下來,回到我們的Retrofit中上薛躬,實(shí)體類已經(jīng)建好了俯渤,我們來看看這個(gè)Retrofit如何進(jìn)行網(wǎng)絡(luò)請求,其實(shí)代碼也很簡單型宝。首先我們需要定義一個(gè)接口八匠,取名RetrofitService :

public interface RetrofitService {

@GET("book/search")

Observable getSearchBooks(@Query("q") String name,

@Query("tag") String tag,@Query("start")intstart,

@Query("count")intcount);

}

額。趴酣。想必有人要問了梨树,這是什么玩意?跟我們平時(shí)定義的接口類很像岖寞,但又不一樣抡四。別心急,我來一一解釋下仗谆,和別的接口類一樣床嫌,我們在其中定義了一個(gè)方法getSearchBook跨释,那么這個(gè)方法是做什么的呢胸私?其實(shí)它干的事很簡單厌处,就是拼接一個(gè)URL然后進(jìn)行網(wǎng)絡(luò)請求。這里我們拼接的URL就是上文提到的測試URL:https://api.douban.com/v2/book/search?q=金瓶梅&tag=&start=0&count=1岁疼。聰明的你一定看出來了阔涉,在這個(gè)URL中book/search就是GET后的值,而?后的q捷绒、tag瑰排、start、count等入?yún)⒕褪沁@個(gè)方法的入?yún)⑴取S械呐笥芽赡芤獑柫送肿。琱ttps://api.douban.com/v2/這么一大串跑哪去了?其實(shí)我們在進(jìn)行網(wǎng)絡(luò)請求時(shí)字逗,在URL中前一部分是相對不變的京郑。什么意思呢,比如你打開間書網(wǎng)站葫掉,在間書中你打開不同的網(wǎng)頁些举,雖然它的URL不同,但你會發(fā)現(xiàn)俭厚,每個(gè)URL前面都是以http://www.reibang.com/開頭,我們把這個(gè)不變的部分户魏,也叫做baseUrl提出來,放到另一個(gè)地方,在下面我們會提到挪挤。這樣我們一個(gè)完整的URL就拼接好了叼丑。在方法的開頭我們可以看到有個(gè)GET的注釋,說明這個(gè)請求是GET方法扛门,當(dāng)然你也可以根據(jù)具體需要用POST鸠信、PUT、DELETE以及HEAD尖飞。他們的區(qū)別如下:

GET ----------查找資源(查)

POST --------修改資源(改)

PUT ----------上傳文件(增)

DELETE ----刪除文件(刪)

HEAD--------只請求頁面的首部

然后我們來看一下這個(gè)方法的返回值症副,它返回Call實(shí)體,一會我們要用它進(jìn)行具體的網(wǎng)絡(luò)請求政基,我們需要為它指定泛型為Book也就是我們數(shù)據(jù)的實(shí)體類贞铣。接下來,你會發(fā)現(xiàn)這個(gè)方法的入?yún)⒑臀覀兤綍r(shí)方法的入?yún)⑦€不大一樣沮明。在每個(gè)入?yún)⑶斑€多了一個(gè)注解辕坝。比如第一個(gè)入?yún)Query("q") String name,Query表示把你傳入的字段拼接起來荐健,比如在測試url中我們可以看到q=金瓶梅的入?yún)⒔闯敲碤uery后面的值必須是q琳袄,要和url中保持不變,然后我們定義了String類型的name纺酸,當(dāng)調(diào)用這個(gè)方法是窖逗,用于傳入字符串餐蔬,比如可以傳入“金瓶梅”碎紊。那么這個(gè)方法就會自動(dòng)在q后面拼上這個(gè)字符串進(jìn)行網(wǎng)絡(luò)請求樊诺。以此類推仗考,這個(gè)url需要幾個(gè)入?yún)⒛憔驮谶@個(gè)方法中定義幾個(gè)入?yún)⒋逝溃總€(gè)入?yún)⑶岸家由螿uery注解秃嗜。當(dāng)然Retrofit除了Query這個(gè)注解外,還有其他幾個(gè)比如:@QueryMap顿膨、@Path锅锨、@Body虽惭、@FormUrlEncoded/@Field橡类、@Header/@Headers芽唇。我們來看一下他們的區(qū)別:

@Query(GET請求):

用于在url后拼接上參數(shù)顾画,例如:

@GET("book/search")

Call getSearchBook(@Query("q") String name);//name由調(diào)用者傳入

相當(dāng)于:

@GET("book/search?q=name")

Call getSearchBook();

@QueryMap(GET請求):

當(dāng)然如果入?yún)⒈容^多,就可以把它們都放在Map中匆笤,例如:

@GET("book/search")

Call getSearchBook(@QueryMapMap options);

@Path(GET請求):

用于替換url中某個(gè)字段研侣,例如:

@GET("group/{id}/users")

Call groupList(@Path("id") int groupId);

像這種請求接口,在group和user之間有個(gè)不確定的id值需要傳入庶诡,就可以這種方法。我們把待定的值字段用{}括起來咆课,當(dāng)然{}里的名字不一定就是id,可以任取书蚪,但需和@Path后括號里的名字一樣。如果在user后面還需要傳入?yún)?shù)的話殊校,就可以用Query拼接上晴玖,比如:

@GET("group/{id}/users")

Call groupList(@Path("id") int groupId,@Query("sort") String sort);

當(dāng)我們調(diào)用這個(gè)方法時(shí),假設(shè)我們groupId傳入1呕屎,sort傳入“2”,那么它拼接成的url就是group/1/users?sort=2秀睛,當(dāng)然最后請求的話還會加上前面的baseUrl尔当。

@Body(POST請求):

可以指定一個(gè)對象作為HTTP請求體,比如:

@POST("users/new")

Call createUser(@BodyUser user);

它會把我們傳入的User實(shí)體類轉(zhuǎn)換為用于傳輸?shù)腍TTP請求體琅催,進(jìn)行網(wǎng)絡(luò)請求居凶。

@Field(POST請求):

用于傳送表單數(shù)據(jù):

@FormUrlEncoded@POST("user/edit")

Call updateUser(@Field("first_name") String first,@Field("last_name") String last);

注意開頭必須多加上@FormUrlEncoded這句注釋藤抡,不然會報(bào)錯(cuò)。表單自然是有多組鍵值對組成缠黍,這里的first_name就是鍵,而具體傳入的first就是值啦药蜻。

@Header/@Headers(POST請求):

用于添加請求頭部:

@GET("user")

Call getUser(@Header("Authorization") String authorization)

表示將頭部Authorization屬性設(shè)置為你傳入的authorization;當(dāng)然你還可以用@Headers表示,作用是一樣的比如:

@Headers("Cache-Control: max-age=640000")

@GET("user")

Call getUser()

當(dāng)然你可以多個(gè)設(shè)置:

@Headers({"Accept: application/vnd.github.v3.full+json","User-Agent: Retrofit-Sample-App"})

@GET("user")

Call getUser()

好了语泽,這樣我們就把上面這個(gè)RetrofitService 接口類解釋的差不多了。我覺得踱卵,Retrofit最主要的也就是這個(gè)接口類的定義了。好了惋砂,有了這個(gè)接口類妒挎,我們來看一下西饵,到底如何使用這個(gè)我們定義的接口來進(jìn)行網(wǎng)絡(luò)請求酝掩。代碼如下:

Retrofit retrofit = new Retrofit.Builder()

.baseUrl("https://api.douban.com/v2/")

.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))

.build();

RetrofitService service = retrofit.create(RetrofitService.class);

Call call =? service.getSearchBook("金瓶梅", null, 0, 1);

call.enqueue(new Callback() {

@Override

public void onResponse(Call call, Response response) {

text.setText(response.body()+"");

}

@Override

public void onFailure(Call call, Throwable t) {

}

});

這里我們可以看到眷柔,先新建了一個(gè)Retrofit對象,然后給它設(shè)置一個(gè)我們前面說的baseUrl:https://api.douban.com/v2/.因?yàn)榻涌诜祷氐臄?shù)據(jù)不是我們需要的實(shí)體類驯嘱,我們需要調(diào)用addConverterFactory方法進(jìn)行轉(zhuǎn)換镶苞。由于返回的數(shù)據(jù)為json類型宙拉,所以在這個(gè)方法中傳入Gson轉(zhuǎn)換工廠GsonConverterFactory.create(new GsonBuilder().create())宾尚,這里我們需要在studio中添加Gson的依賴:

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

然后我們調(diào)用retrofit的create方法并傳入上面我們定義的接口的文件名RetrofitService.class,就可以得到RetrofitService 的實(shí)體對象。有了這個(gè)對象煌贴,我們就可以調(diào)用里面之前定義好的請求方法了御板。比如:

Callcall=? service.getSearchBook("金瓶梅",null,0,1);

它會返回一個(gè)Call實(shí)體類,然后就可以調(diào)用Call的enqueue方法進(jìn)行異步請求牛郑,在enqueue方法中傳入一個(gè)回調(diào)CallBack怠肋,重寫里面的onResponse和

onFailure方法,也就是請求成功和失敗的回調(diào)方法淹朋。當(dāng)成功時(shí)笙各,它會返回Response,里邊封裝了請求結(jié)果的所有信息础芍,包括報(bào)頭杈抢,返回碼,還有主體等仑性。比如調(diào)用它的body()方法就可獲得Book對象惶楼,也就是我們需要的數(shù)據(jù)。這里我們就把返回的Book诊杆,顯示屏幕上歼捐。如下圖:

Book中的數(shù)據(jù)

好了,到這里我們就基本了解了Retrofit的整個(gè)工作流程晨汹。

3.RxJava

我們這篇文章主要介紹搭建整體網(wǎng)絡(luò)請求框架豹储,所以關(guān)于RxJava的基礎(chǔ)知識淘这,我這就不再詳細(xì)介紹了,網(wǎng)上也有很多文章慨灭,對RxJava還不是很了解的同學(xué)朦乏,推薦你看一下拋物線的這篇文章給 Android 開發(fā)者的 RxJava 詳解

感興趣可以接著看下一篇:

http://www.reibang.com/p/d62fd00dfd76


參考文章:http://www.reibang.com/p/7b839b7c5884

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末氧骤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子筹陵,更是在濱河造成了極大的恐慌,老刑警劉巖朦佩,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異语稠,居然都是意外死亡弄砍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門音婶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莱坎,“玉大人衣式,你說我怎么就攤上這事檐什〔晡裕” “怎么了乃正?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長烫葬。 經(jīng)常有香客問我,道長搭综,這世上最難降的妖魔是什么划栓? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮忠荞,結(jié)果婚禮上蒋歌,老公的妹妹穿的比我還像新娘委煤。我一直安慰自己,他們只是感情好碧绞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讥邻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兴使。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天发魄,我揣著相機(jī)與錄音,去河邊找鬼。 笑死汰寓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的踩寇。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼俺孙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了睛榄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤场靴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后旨剥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轨帜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哮兰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喝滞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出右遭,到底是詐尸還是另有隱情,我是刑警寧澤荔睹,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站僻他,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏吨拗。R本人自食惡果不足惜婿斥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一哨鸭、第九天 我趴在偏房一處隱蔽的房頂上張望民宿。 院中可真熱鬧像鸡,春花似錦活鹰、人聲如沸只估。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吁脱,卻和暖如春桑涎,著一層夾襖步出監(jiān)牢的瞬間兼贡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工遍希, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孵班。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓招驴,卻偏偏與公主長得像篙程,于是被迫代替她去往敵國和親别厘。 傳聞我的和親對象是個(gè)殘疾皇子虱饿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容