之前公司的項目用到了MVP+Retrofit+RxJava的框架進行網絡請求,所以今天特此寫一篇文章以做總結。相信很多人都聽說過MVP、Retrofit、以及RxJava,有的人已經開始用了,有的人可能還不知道這是什么,以及到底怎么用。不過沒關系,接下來我將為你一一揭開他們的神秘面紗,然后利用這三個家伙搭建一個網絡請求框架
1.什么是MVP?
MVP(Model View Presenter)其實就是一種項目的整體框架,能讓你的代碼變得更加簡潔,說起框架大家可能還會想到MVC、MVVM。由于篇幅原因,這里我們先不講MVVM,先來看一下MVC。其實Android本身就采用的是MVC(Model View Controllor)模式、其中Model指的是數據邏輯和實體模型;View指的是布局文件、Controllor指的是Activity。對于很多Android初學者可能會有這樣的經歷,寫代碼的時候,不管三七二十一都往Activity中寫,當然我當初也是這么干的,根本就沒有什么框架的概念,只要能實現某一個功能就很開心了,沒有管這么多。當然項目比較小還好,一旦項目比較大,你會發現,Activity所承擔的任務其實是很重的,它既要負責頁面的展示和交互,還得負責數據的請求和業務邏輯之類的工作,相當于既要打理家庭,又要教育自己調皮的孩子,真是又當爹又當媽。。。那該怎么辦呢?這時候Presenter這個繼父來到了這個家庭。Presenter對Activity說,我來了,以后你就別這么辛苦了,你就好好打理好View這個家,我專門來負責教育Model這孩子,有什么情況我會向你反映的。這時Activity流下了幸福的眼淚,從此,Model、View(Activity)、Presenter一家三口過上了幸福的生活。。。好了磕個藥繼續,由于Presenter(我們自己建的類)的出現,可以使View(Activity)不用直接和Model打交道,View(Activity)只用負責頁面的顯示和交互,剩下的和Model交互的事情都交給Presenter做,比如一些網絡請求、數據的獲取等,當Presenter獲取到數據后再交給View(Activity)進行展示,這樣,Activity的任務就大大減小了。這便是MVP(Model 還是指的數據邏輯和實體模型,View指的是Activity,P就是Presenter)框架的工作方式。
2.什么是Retrofit?
接下來我們看一下什么是Retrofit。在官網對Retrofit的描述是這樣的
A type-safe HTTP client for Android and Java說人話就是“一個類型安全的用于Android和Java網絡請求的客戶端”,其實就是一個封裝好的網絡請求庫。接下來就來看一下這個庫該怎么用。首先我在網上找了一個API接口用于測試:https://api.douban.com/v2/book/search?q=金瓶梅&tag=&start=0&count=1這是一個用于查詢一本書詳細信息的一個請求接口。如果直接用瀏覽器打開的話會返回以下內容:
瀏覽器中返回內容
接下來我們來看看如何用Retrofit將上面的請求下來。為了在Android Studio中添加Retrofit庫,我們需要添加如下依賴:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
好了,添加完該庫,我們再來看看如何使用,首先我們來建一個實體類Book,用于裝網絡請求后返回的數據。這里順帶說一下,有的人建一個實體類時可能會根據瀏覽器中返回中的數據一行一行敲,其實這樣非常麻煩,這里教大家一個簡單的方法,瞬間生成一個實體類。沒錯有的人可能用過,我們需要一個插件GsonFormat。它的使用也很簡單,首先需要在Android Studio中下載,點擊左上角菜單欄中的File,然后點擊Settings,在彈窗中選擇Plugins,然后點擊下方的Browse repositories...
然后在新打開的窗口中搜索GsonFormat,點擊右側綠色按鈕就可以下載安裝了,安裝完需要重啟下studio,就可以用了。
它的用法也很簡單,比如你先建立一個新的空類取名Book,然后在里面按Alt+insert,會有個小彈窗選擇GsonFormat,之后在彈出的編輯框中拷入在瀏覽器中請求下來的那一坨東西,然后一直點ok就會自動生成字段,以及set和get方法,一會兒我們用Retrofit請求下來的數據都會保存在這個實體類中,還是挺方便的。最后我們里面添加一個toString()方法,用于后面顯示方便。
接下來,回到我們的Retrofit中上,實體類已經建好了,我們來看看這個Retrofit如何進行網絡請求,其實代碼也很簡單。首先我們需要定義一個接口,取名RetrofitService :
public interface RetrofitService {
@GET("book/search")
Observable getSearchBooks(@Query("q") String name,
@Query("tag") String tag,@Query("start")intstart,
@Query("count")intcount);
}
額。。想必有人要問了,這是什么玩意?跟我們平時定義的接口類很像,但又不一樣。別心急,我來一一解釋下,和別的接口類一樣,我們在其中定義了一個方法getSearchBook,那么這個方法是做什么的呢?其實它干的事很簡單,就是拼接一個URL然后進行網絡請求。這里我們拼接的URL就是上文提到的測試URL:https://api.douban.com/v2/book/search?q=金瓶梅&tag=&start=0&count=1。聰明的你一定看出來了,在這個URL中book/search就是GET后的值,而?后的q、tag、start、count等入參就是這個方法的入參。有的朋友可能要問了,https://api.douban.com/v2/這么一大串跑哪去了?其實我們在進行網絡請求時,在URL中前一部分是相對不變的。什么意思呢,比如你打開間書網站,在間書中你打開不同的網頁,雖然它的URL不同,但你會發現,每個URL前面都是以http://www.lxweimin.com/開頭,我們把這個不變的部分,也叫做baseUrl提出來,放到另一個地方,在下面我們會提到。這樣我們一個完整的URL就拼接好了。在方法的開頭我們可以看到有個GET的注釋,說明這個請求是GET方法,當然你也可以根據具體需要用POST、PUT、DELETE以及HEAD。他們的區別如下:
GET ----------查找資源(查)
POST --------修改資源(改)
PUT ----------上傳文件(增)
DELETE ----刪除文件(刪)
HEAD--------只請求頁面的首部
然后我們來看一下這個方法的返回值,它返回Call實體,一會我們要用它進行具體的網絡請求,我們需要為它指定泛型為Book也就是我們數據的實體類。接下來,你會發現這個方法的入參和我們平時方法的入參還不大一樣。在每個入參前還多了一個注解。比如第一個入參@Query("q") String name,Query表示把你傳入的字段拼接起來,比如在測試url中我們可以看到q=金瓶梅的入參,那么Query后面的值必須是q,要和url中保持不變,然后我們定義了String類型的name,當調用這個方法是,用于傳入字符串,比如可以傳入“金瓶梅”。那么這個方法就會自動在q后面拼上這個字符串進行網絡請求。以此類推,這個url需要幾個入參你就在這個方法中定義幾個入參,每個入參前都要加上Query注解。當然Retrofit除了Query這個注解外,還有其他幾個比如:@QueryMap、@Path、@Body、@FormUrlEncoded/@Field、@Header/@Headers。我們來看一下他們的區別:
@Query(GET請求):
用于在url后拼接上參數,例如:
@GET("book/search")
Call getSearchBook(@Query("q") String name);//name由調用者傳入
相當于:
@GET("book/search?q=name")
Call getSearchBook();
@QueryMap(GET請求):
當然如果入參比較多,就可以把它們都放在Map中,例如:
@GET("book/search")
Call getSearchBook(@QueryMapMap options);
@Path(GET請求):
用于替換url中某個字段,例如:
@GET("group/{id}/users")
Call groupList(@Path("id") int groupId);
像這種請求接口,在group和user之間有個不確定的id值需要傳入,就可以這種方法。我們把待定的值字段用{}括起來,當然{}里的名字不一定就是id,可以任取,但需和@Path后括號里的名字一樣。如果在user后面還需要傳入參數的話,就可以用Query拼接上,比如:
@GET("group/{id}/users")
Call groupList(@Path("id") int groupId,@Query("sort") String sort);
當我們調用這個方法時,假設我們groupId傳入1,sort傳入“2”,那么它拼接成的url就是group/1/users?sort=2,當然最后請求的話還會加上前面的baseUrl。
@Body(POST請求):
可以指定一個對象作為HTTP請求體,比如:
@POST("users/new")
Call createUser(@BodyUser user);
它會把我們傳入的User實體類轉換為用于傳輸的HTTP請求體,進行網絡請求。
@Field(POST請求):
用于傳送表單數據:
@FormUrlEncoded@POST("user/edit")
Call updateUser(@Field("first_name") String first,@Field("last_name") String last);
注意開頭必須多加上@FormUrlEncoded這句注釋,不然會報錯。表單自然是有多組鍵值對組成,這里的first_name就是鍵,而具體傳入的first就是值啦。
@Header/@Headers(POST請求):
用于添加請求頭部:
@GET("user")
Call getUser(@Header("Authorization") String authorization)
表示將頭部Authorization屬性設置為你傳入的authorization;當然你還可以用@Headers表示,作用是一樣的比如:
@Headers("Cache-Control: max-age=640000")
@GET("user")
Call getUser()
當然你可以多個設置:
@Headers({"Accept: application/vnd.github.v3.full+json","User-Agent: Retrofit-Sample-App"})
@GET("user")
Call getUser()
好了,這樣我們就把上面這個RetrofitService 接口類解釋的差不多了。我覺得,Retrofit最主要的也就是這個接口類的定義了。好了,有了這個接口類,我們來看一下,到底如何使用這個我們定義的接口來進行網絡請求。代碼如下:
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) {
}
});
這里我們可以看到,先新建了一個Retrofit對象,然后給它設置一個我們前面說的baseUrl:https://api.douban.com/v2/.因為接口返回的數據不是我們需要的實體類,我們需要調用addConverterFactory方法進行轉換。由于返回的數據為json類型,所以在這個方法中傳入Gson轉換工廠GsonConverterFactory.create(new GsonBuilder().create()),這里我們需要在studio中添加Gson的依賴:
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
然后我們調用retrofit的create方法并傳入上面我們定義的接口的文件名RetrofitService.class,就可以得到RetrofitService 的實體對象。有了這個對象,我們就可以調用里面之前定義好的請求方法了。比如:
Callcall=? service.getSearchBook("金瓶梅",null,0,1);
它會返回一個Call實體類,然后就可以調用Call的enqueue方法進行異步請求,在enqueue方法中傳入一個回調CallBack,重寫里面的onResponse和
onFailure方法,也就是請求成功和失敗的回調方法。當成功時,它會返回Response,里邊封裝了請求結果的所有信息,包括報頭,返回碼,還有主體等。比如調用它的body()方法就可獲得Book對象,也就是我們需要的數據。這里我們就把返回的Book,顯示屏幕上。如下圖:
Book中的數據
好了,到這里我們就基本了解了Retrofit的整個工作流程。
3.RxJava
我們這篇文章主要介紹搭建整體網絡請求框架,所以關于RxJava的基礎知識,我這就不再詳細介紹了,網上也有很多文章,對RxJava還不是很了解的同學,推薦你看一下拋物線的這篇文章給 Android 開發者的 RxJava 詳解
感興趣可以接著看下一篇:
http://www.lxweimin.com/p/d62fd00dfd76