Retrofit2.0使用文檔

參考資料:

http://blog.csdn.net/u014165119/article/details/49280779
https://github.com/square/okhttp/tree/master/samples  OkHttp的Sample
http://blog.csdn.net/ljd2038/article/details/51189334   文件下載案例

系列文章資料:

這是我對Retorfit2.0源碼的一些解讀,有問題希望大家指正
Retrofit2.0中的Builder模式
Retrofit2.0中的動態代理模式
Retrofit2.0中的適配器模式
Retrofit2.0中的策略模式

一、為什么使用Retrofit2.0

(1).Retrofit2.0是由Square公司開發的一個網絡請求框架,已經成為Android開發中非?;馃岬囊粋€庫。是Square公司對OkHttp進行再次封裝的框架。

Paste_Image.png

Google在大概Android4.3(具體不太清楚了)的時候已經不推薦使用HttpClient ,改為用推薦使用OkHttp,在6.0的時候更是刪除了HttpClient,Retrofit作為Square公司推出的對Okhttp再次封裝得庫,無疑對OkHttp支持的更好。對比現在主流的網絡框架Volly,Volly針對不同的返回類型,需要調用不同的方法,傳入參數也非常麻煩,而Retrofit在調用一個接口時,就像是在調用一個本地方法。同時Retrofit采用鏈式編程的方式,讓代碼的邏輯結構更加清晰。Retrofit非常靈活,可以做到動態的去配置Url。同時它非常適合RESTFUL API的形式。

示例服務端代碼:

@Controller
@EnableWebMvc
@RequestMapping(headers="Accept=*/*", 
 produces="application/json")

public class LoginController {

    @Resource
    LoginService service;// 自動依賴注入
    @Resource
    LoginEntity userEntity;
    @Resource
    ResultEntity resultEntity;
    @RequestMapping(value = "login", method = RequestMethod.GET,produces = "application/json",headers="Accept=*/*")
    @ResponseBody
    public 
 ResultEntity login(HttpServletRequest
 request,HttpServletResponse response) {
        //拿到服務器端的參數
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (service.isExitsPeople(username, password)==1) {
            userEntity.setUsername(username);
            userEntity.setPassword(password);
            resultEntity.setIsSuccess(true);
            resultEntity.setMessage("登錄成功");
            resultEntity.setResult(userEntity);
            return  resultEntity;
        }else{
            resultEntity.setIsSuccess(false);
            resultEntity.setMessage("登錄失敗");
            resultEntity.setResult("");
            return resultEntity;
        }    
       //System.out.println("測試login方法是否成功" + service.getUserCount(username, password));
       // System.out.println("測試MyBatis使用是否成功" + service.isExitsPeople(username, password));
    }
}

示例Retrofit api的代碼

示例客戶端API代碼:
public interface LoginService {
@FormUrlEncoded
@POST("Member/Login")
    Call<UserModel>
loginApp(@Field("username") String name, @Field("password")
String pwd               
}

(2).它的請求速度非???br> 圖片來自:
http://blog.csdn.net/xiongge358/article/details/50990864

Paste_Image.png

示例代碼:

public
 class RetrofitClient {
    private Retrofit client;
    private String BaseUrl;
    /**
     * 初始化Retrofit的內容
     */
    public RetrofitClient(String BaseUrl) {
        this.BaseUrl = BaseUrl;
        client = new Retrofit.Builder()     
 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
 .addConverterFactory(GsonConverterFactory.create(
 .baseUrl(BaseUrl)
 .build();
    }
    public SmileAPI getSmileAPI() {
        return client.create(SmileAPI.class);
    }
    public WeatherAPI getWeatherAPI() {
        return client.create(WeatherAPI.class);
    }
}

二、配置Retrofit2.0

在Moudel的gradle中配置

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

同樣Retrofit也可以對OkHttp進行自己的定制,所以如果需要定制OkHttp同樣可以引入Okhttp的庫

 compile 'com.squareup.okhttp3:okhttp:3.3.1'

三、使用Retrofit2.0

1.配置Retrofit

***baseUrl:****

  1. 默認的服務器地址,Retrofit在進行請求一個接口時會根據你填寫的 baseurl+方法名 去請求。

****addConverterFactory:****

添加返回數據的解析方式,Retrofit支持多種格式的解析,xml,json,jackson,Moshi,Protobuf,wire等,添加對這些數據格式的支持同樣需要在Gradle中進行依賴。這些依賴Square公司同樣提供了支持。
這里是Square提供的官方Converter modules列表。選擇一個最滿足你需求的。

Gson: com.squareup.retrofit:converter-gson
Jackson: com.squareup.retrofit:converter-jackson
Moshi: com.squareup.retrofit:converter-moshi
Protobuf: com.squareup.retrofit:converter-protobuf
Wire: com.squareup.retrofit:converter-wire
Simple XML: com.squareup.retrofit:converter-simplexml

****CallAdapter:****

Retrofit會將網絡請求的接口以回調的方式返回,我們通常會得到一個叫做Call<類型>的結果,如果我們需要返回其他的結果,例如RxJava形式的結果,需要對RxJava做支持。如果不需要特殊類型的返回結果,我們是不需要配置的。

****Client:****

通過該方法我們可以添加自己定制的OkHttp。
定制OkHttp

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(interceptor)
        .retryOnConnectionFailure(true)
        .connectTimeout(15, TimeUnit.SECONDS)
        .addNetworkInterceptor(mTokenInterceptor)
        .build();
//將定制的OkHttp加入到Retrofit中
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(AppConfig.BASE_URL)
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(client)
        .build();
```
***Create:***
如果一切都配置好了,那么通過調用Create,并傳入你的接口方法類型,就可以請求服務端了。
使用Retrofit

####一、  定義請求的接口
Retrofit非常適合Restful API,它采用注解,加動態代理的方式去請求一個服務。
1.     **定義你要請求的接口**

因為Retrofit采用動態代理的方式去請求一個接口,所以在定義我們需要請求的接口時,我們需要定義一個接口,并添加相應的注解,告訴Retrofit如何請求我們需要的接口。參數的返回類型默認情況下需要通過Call方法進行包裝。

```
public interface LoginService {
@FormUrlEncoded
@POST("Member/Login")
  Call<UserModel>loginApp(@Field("username") String name, @Field("password")String pwd  ,@Field("grid") String grid);
}
```
 

####二、   Retrofit的注解

**方法上的注解**

1.請求的類型
```
@POST
@GET
參數:請求的方法,對應接口文檔的方法名。
```
2.添加靜態的頭部協議
```
@Headers
例如:@Headers("Cache-Control: max-age=640000")
```
3.數據提交的方式
```
@FormUrlEncoded
添加該注解后,將會發送form-encode的數據類型
```
4.數據提交的方式
```
@Multipart
添加該注解后,將會發送Mulitipar類型的數據。
```
**參數注解**

```
1.@Part:如果你在方法注解上加入了@Multipart,那么對應的方法參數必須要用該注解
```
 
```
2.@Field:如果你在方法注解上加入了@FormUrlEncoded注解,那么對應的方法參數必須用該注解。
```
 
```
3.   @Body:如果傳遞的是一個序列化的參數
例如:@POST("users/new")
Call<User> createUser(@Body User user);
```
 

**Retrofit請求的Url同樣是可以動態配置的。請求的URL可以在函數中使用替換塊和參數進行動態更新,替換塊是{ and }包圍的字母數字組成的字符串。
**

```
3.@Path :Url中有一段是需要動態配置的時候
例如:
@GET("group/{id}/users")
List<User>
groupList(@Path("id") int groupId);

``` 
 
```
4.@Query 查詢參數
例如:
@GET("group/{id}/users")
```

```
List<User> groupList(@Path("id") int groupId,
@Query("sort") String sort);
```
 

5.復雜的參數同樣可以通過Map方式

```
例如:
@GET("group/{id}/users")
List<User>
groupList(@Path("id") int groupId, @QueryMap Map<String,
String> options);

 ```

 

####四、處理Call返回的參數

1. 如果我們定義好了接口。那么這個時候就可以調用create方法,并且傳入我們需要請求的接口類型,拿到返回值了。
使用Call:

例子:
```
 MyService service =retrofit.create(MyService.class);
 Call<ResultModel<UserInfoModel>>call = service.loginApp("","");
 Service.loginApp:就是執行我們定義的方法,并且拿到返回值。
``` 

2. 接著我們使用Call:
```
call.enqueue(new Callback<Repo>() {
   @Override
public void onResponse(Response<UserInfoModel response) {
       // 通過reponse拿到結果
      UserModelInfo info=response.body();
    }  
     @Override
     public void onFailure(Throwable t) {  
   }
});
```
 

####五、Retrofit實現文件上傳(方式1)

1.使用@Mulitpart注解標記接口 
2.@Part              注解標記文件類型的參數
3.MultipartBody.Part   標記文件的參數

 ```
public interface FileUploadService {  
 @Multipart
 @POST("upload")
 Call<ResponseBody> upload(@Part("description") RequestBody description,
                          @Part MultipartBody.Part file);
}
 ```

4.使用RequestBody包裝上傳文件

```
//構建要上傳的文件
File file = new File(filename);
RequestBody requestFile =RequestBody.create(MediaType.parse("multipart/form-data"),file);
```
***注:MediaType.parse 參數代表上傳文件的類型(Content-Type)的類型,例如:如果是上傳的是圖片,可以寫成MediaType.parse("image/jpg")***


5.使用MultipartBody.Part對Request再次包裝

```
//構建要上傳的文件
參數1:對應的接口參數
參數2:上傳的文件名稱
參數3:包裝的RequestBody

MultipartBody.Part body = MultipartBody.Part.createFormData("aFile", file.getName(),
requestFile);
```
 

 

6.調用上傳方法:
```
Call<ResponseBody> call = service.upload(description,body);
```
####六、Retrofit實現文件上傳(方式2)

1.通過定義自己的FileConvertFactory,我們可以將File類型,不通過包裝,作為參數傳入。
```
public interface FileUploadService {     
@Multipart   
@POST("upload")                    //注意這里的參數 "aFile" 之前是在創建MultipartBody.Part 的時候傳入的
Call<ResponseBody> upload(@Part("description") RequestBody description,       
@Part("aFile") File file);
}
```
 
####7.使用ConvertFactory進行上傳

繼承Converter.Factory :
```
static class FileRequestBodyConverterFactory extends Converter.Factory {
@Override
public Converter<File, RequestBody> requestBodyConverter(Type type, Annotation[]
parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {   
return new FileRequestBodyConverter();
  }
}
static class FileRequestBodyConverter implements Converter<File, RequestBody> {
 @Override
  public RequestBody convert(File file) throws IOException {   
return RequestBody.create(MediaType.parse("application/otcet-stream"),file); 
 }
}
```
2.在配置Retrofit時加入我們自己的文件類型支持

```
.addConverterFactory(new
FileRequestBodyConverterFactory())
```

####七、文件下載

使用Okhttp的ReponseBody做為返回類型

示例代碼: 
```
Call<ResponseBody> call =mService.getFile();
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody>
response) {
       try {
            writeResponseBodyToDisk(MainActivity.this, response.body());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void
onFailure(Call<ResponseBody> call, Throwable t) {
        Log.e("H", "result
: " + t.toString());
    }
});
```
 

 

ReponseBody會拿到文件流,對拿到的文件流做處理
示例代碼:

```
public boolean writeResponseBodyToDisk(Context context, ResponseBody body) throws IOException {
    Log.d("tag","開始下載"+"/"+body.contentType().toString());
    boolean flag = true;
    String type =
    body.contentType().toString();

 if (type.equals(".apk")) {
        mFileSuffix = ".apk";
    } else if (type.equals(".png")) {
        mFileSuffix = ".png";
   } 
 else if(type.equals(".jpg")) {
   mFileSuffix = ".jpg"; }
    if (type.equals(".zip")) {
        mFileSuffix = ".zip";
    }
    // 其他同上 自己判斷加入
    final String name ="guo"+System.currentTimeMillis() + mFileSuffix;
    final String path =Environment.getExternalStorageDirectory() + File.separator + name;
    /**
     * 寫入流
     */
    InputStream is = body.byteStream();
    File file = new File(path);
    FileOutputStream fos = new FileOutputStream(file);
    BufferedInputStream bis = new BufferedInputStream(is);
    byte[] buffer = new byte[1024];
    int len;
    while ((len = bis.read(buffer)) !=-1) {
        fos.write(buffer, 0, len);
        fos.flush();
    }
    fos.close();
    bis.close();
    is.close();
    Log.d("tag","下載完畢");
    return flag;
}
```
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容