Android框架第(五)篇---Retrofit基本使用

b10l07發表於2017-12-04

**版權宣告:本文為小斑馬偉原創文章,轉載請註明出處!

2878032-55e124d08032d5a1.png

Retrofit:(A type-safe HTTP client for Android and Java)通過註解的方式描述HTTP請求,底層由OKHttp實現 看成是對OKHttp的一次封裝,採用註解方式來描述HTTP請求。非常適合RESTFul風格的網路請求,目前版本2.0.0.

一、 RESTful

REST:是 “REpresentational State TRransfer” 的縮寫,即"表現層狀態轉換"。表現層:網路上資源的變現形式(資源:是網路上的一個實體,或者說網路上的具體資訊,可以是一段文字、一張圖片、一首歌曲、一種服務。總之就是具體的實在。我們可以用一個URI,統一定向符指向它。每種資源對應一個特定的URI,要獲取它的資源,就要訪問它的URI。因此URI就成為每一個資源的地址,或者獨一為二識別符。我們常說的上網就是網際網路上的資源的互動,呼叫它的URI。表現層就是網路資源的一種表現形式。資源是實體資訊,它可以多種外在的形式,我們把資源具體呈現出的資訊,我們叫它表現層。比如文字可以用txt形式表現,也可以用html形式表現。URI只代表資源的實體。不代表資源的形式。嚴格上來說,某些檔案的字尾名是可以不需要的,因為它是表示格式,表示表現層的範疇。而URI只表示資源的位置。它的具體表現形式,應該在HTTP請求的頭部資訊中,用Content-Type和Obser形式指定)。
狀態轉換:客戶端通過某種手段使得伺服器上資源發生變化,訪問一個網站,肯定會涉及到客戶端和服務端互動過程,在這個過程中,勢必涉及到資料和狀態的轉換,網際網路的協議是HTTP狀態的協議,這就意味著所有的狀態必須儲存在伺服器端,如果客戶端要運算元據,就必須通過某種手段,讓伺服器端發生狀態轉換。而這種轉化是建立在表現層上的,所以就是表現層的狀態轉換。而客戶端使用的手段,只能是HTTP的協議,具體的說就是HTPP裡面具體四個操作符的動詞,GET POST PATH DELETE。

二、 RESRful架構
  • 1、每一個URI代表一種資源,而不是對資源的一種操作。
  • 2、客戶端和伺服器之間,傳遞這種資源的某種表現層。
  • 3、客戶端通過HTTP動作,對服務端資源進行操作。
三、Retrofit引入

compile’com.squareup.retrofit2:retrofit:2.0.1'

四、Retrofit請求網路流程*

定義一個URL:http://192.168.31.242:8080/android/user/users

  • 3.1 定義一個介面物件

     public interface IUserInfo {
        GET("users")
        Call<List<User>> getUsers();
    }
    
  • 3.2 構造Retrofit物件

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://192.168.31.242:8080/android/user/")
        .addConverterFactory(GsonConverterFactory.create()) //json格式轉換器
        .build();
    
  • 3.3 拿到介面物件的例項

    IUserInfo userInfo = retrofit.create(IUserInfo.class);
    
  • 4.3由介面物件生成call物件,並執行網路請求

    Call<List<User>> call = userInfo.getUsers();
    call.enqueue(new Callback<List<User>>() {
         @Override
         public void onResponse(Call<List<User>> call, Response<List<User>> response)
         {
            Log.i(TAG,"onResponse:"+response.body()+"");
         }
         @Override
         public void onFailuse(Call<List<User>>call, Throwable t){}
         });
    
五、Retrofit常用註解 - @Path

1.用於訪問zhangsan的資訊
http://192.168.1.102:8080/android/user/users/zhangsan
2.用於訪問lisi的資訊
http://192.168.1.102:8080/android/user/users/lisi
這種風格URL只是符合RESTful的設計風格的,URL只表示資源資訊,因為我們在這個URL看不到任何的網路資訊的請求。這個請求在我們的html方法中來執行。這種的型別的API就是RESRful的API。

public interface IUserInfo {
    @GET("{username}") //佔位符 通過傳遞來到引數進行替換
    Call<User> getUser(@Path("username") String username);
}

//Call<User> call = userInfo.getUser("zhangsan")
 Call<User> call = userInfo.getUser("lisi");                              
五、Retrofit常用註解 - @Query

1.用於訪問zhangsan的資訊
http://192.168.1.102:8080/android/user/users/?name=zhangsan
2.用於訪問lisi的資訊
http://192.168.1.102:8080/android/user/users/?name=lisi

public interface IUserInfo {
    GET("users")
    Call<List<User>> getUsersByName(@Query("name") String name); //定義一個key:name 後面傳遞來的引數。通過Query註解來拼接,把key:name和後面傳遞來的name拼接成一個鍵值對。然後把這個鍵值對加到URL後面。
 }
//Call<List<User>> call = userInfo.getUserByName("zhangsan");
 Call<List<User>> call = userInfo.getUserByName("lisi");

定義一個key:name 後面傳遞來的引數。通過Query註解來拼接,把key:name和後面傳遞來的name拼接成一個鍵值對。然後把這個鍵值對加到URL後面。

六、Retrofit常用註解 - @Body(一般用於POST)請求
public interface IUserInfo {
   @POST("users")
   Call<List<User>> addUser(@Body User user);
}

Call<User> call = userInfo.addUser(new User(236,"zhangsan")); //把一個json物件的字串傳送給伺服器的

通過POST定義是一個POST請求,POST後面的請求的值和baseUrl組成一個完成的請求的URL的路徑,然後定義了一個方法addUser新增使用者,通過Body註解在呼叫這個方法的時候,只需要傳遞一個物件。這個註解自動把這個物件轉換成json字串。新增到我們網路請求的Body中,發給伺服器。定義這個介面後,如果我們新增一個張三,通過userInfo事例的addUser方法,傳遞來一個User就OK。

七、Retrofit常用註解 - @FormUrlEncoded 表示以表單的形式傳遞鍵值對。
public interface IUserInfo {
    @POST("register")
    @FormUrlEncoded
    Call<User> register(@Field("userid") String userid, @Field("username") String username);
}

Call<User> call = userInfo.register("123","zhangsan"); //FormUrlEncoded註解自動的將123和zhangsan 以及userid和username拼接成鍵值對的方式,傳送給伺服器。
八、Retrofit常用註解 - @Multipart (表示單檔案上傳)
public interface IUserInfo {
    @Multipart //多個Part
    @POST("register")
    Call<User> register(@Part MultipartBody.Part icon, @Part("userid") RequestBody userid); //1.part 表示上傳的檔案,第二個part表示是一個鍵值對,表示使用者的ID
}

發起GET請求

private void getRequest() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    IGetInfos getInfos = retrofit.create(IGetInfos.class);

    Call<ResponseCategory> call = getInfos.getCategories();
    call.enqueue(new Callback<ResponseCategory>() {
        @Override
        public void onResponse(Call<ResponseCategory> call, Response<ResponseCategory> response) {
            ResponseCategory responseCategory = response.body();
            Log.i("data","onResponse() success !!");
        }

        @Override
        public void onFailure(Call<ResponseCategory> call, Throwable t) {

        }
    });
}

private String baseUrl = "http://35.185.149.228";

private class ResponseCategory {

    public int status;

    public List<CategoryMode> date;

    public class CategoryMode {
        public int id;
        public String name;
    }
}
private interface  IGetInfos {
    @GET("user/get-big-direction")
    Call<ResponseCategory> getCategories();
}

發起POST上傳鍵值對(登入)

 private void postPairs() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    IUserLogin userLogin = retrofit.create(IUserLogin.class);

    Call<RespLoginModel> call = userLogin.login("sda","233");
    call.enqueue(new Callback<RespLoginModel>() {
        @Override
        public void onResponse(Call<RespLoginModel> call, Response<RespLoginModel> response) {
            RespLoginModel responseCategory = response.body();
            Log.i("data","onResponse() success !!");
        }

        @Override
        public void onFailure(Call<RespLoginModel> call, Throwable t) {

        }
    });
}

public class RespLoginModel {
    public int status;
    public User data;

    public class User {
        private String id;
        private String username;
        private String avatar;
    }
}

public interface  IUserLogin{
    @POST("user/do-login")
    @FormUrlEncoded
    Call<RespLoginModel> login(@Field("login-username") String username,@Field("login-password") String password);
}

上傳檔案

 private void upLoad() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    IUpLoadIcon upLoadIcon = retrofit.create(IUpLoadIcon.class);

    File file = new File(Environment.getExternalStorageDirectory()+"ic_laucher.png");
    RequestBody photoBody = RequestBody.create(MediaType.parse("imge/png"),file);

    MultipartBody.Part phone = MultipartBody.Part.createFormData("uplaodImg[file]",file.getName(),photoBody);
    Call<RespUpLoadModel> call = upLoadIcon.upLoadIcon(phone);

    call.enqueue(new Callback<RespUpLoadModel>() {
        @Override
        public void onResponse(Call<RespUpLoadModel> call, Response<RespUpLoadModel> response) {
            RespUpLoadModel responseCategory = response.body();
            Log.i("data","onResponse() success !!");
        }

        @Override
        public void onFailure(Call<RespUpLoadModel> call, Throwable t) {

        }
    });
}

public class RespUpLoadModel {
    private int status;

    private Img data;

    private class Img {
        private String img_url;
    }
}

public interface  IUpLoadIcon {
    @POST("file/upload-img")
    @Multipart
   Call<RespUpLoadModel> upLoadIcon(@Part MultipartBody.Part phone);
}

Retrofit網路請求:本質上是OKHttp完成,而Retrofit僅負責網路請求的介面的封裝。實際上就是使用Retrofit的介面封裝我們請求的引數Hearder頭部,URL資訊等等,最後交給OKHttp來完成後續的網路請求操作。在服務端返回資料給我們,OkHttp將原始的介面交給Retrofit。Retrofit根據使用者的需求對結果進行不同型別的解析。
Retrofit進行網路請求的主要步驟:
1.建立描述網路請求的介面
定義方法和相應的註解:其內部通過動態代理的模式,將我們介面和它的註解轉換成一個HTTP請求,最後再去執行我們的HTTP請求。
介面裡面的方法和引數,都必須要用註解的方式標註,否者不標註就會出錯。
2.建立Retrofit例項
3.建立網路請求介面例項並配置網路請求引數
4.傳送網路請求(非同步或者同步)
5.處理伺服器返回的資料

相關文章