OkHttp,Retrofit 1.x - 2.x 基本使用

KingsLanding發表於2016-01-30

  Square 為廣大開發者奉獻了OkHttp,Retrofit1.x,Retrofit2.x,運用比較廣泛,這三個工具有很多相似之處,初學者可能會有一些使用迷惑。這裡來總結一下它們的一些基本使用和一些細微差別。

/**************
Retrofit 基本使用方法

Retrofit 到底是返回什麼? void, Observable, Call?

*************/
/********************************************Retrofit****************************************************************/
/*** 同步呼叫的方式  ****/
interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  List<Contributor> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
} 

List<Contributor> contributors =
    gitHubService.repoContributors("square", "retrofit");
/***** 非同步呼叫的方式 僅限於 Retrofit 1.x !!!!!!! *****/
interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  void repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo,
      Callback<List<Contributor>> cb); // 非同步呼叫新增 CallBack
} 

service.repoContributors("square", "retrofit", new Callback<List<Contributor>>() {
  @Override void success(List<Contributor> contributors, Response response) {
    // ...
  }


  @Override void failure(RetrofitError error) {
    // ...
  }
});

/**** Rxjava 方式 ****/
interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Observable<List<Contributor>> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
} 
// 呼叫
gitHubService.repoContributors("square", "retrofit")
    .subscribe(new Action1<List<Contributor>>() {
      @Override public void call(List<Contributor> contributors) {
        // ...
      }
    });
    
/*******************************注意以下三個Callback的不同***************************************/
	
// Retrofit Callback Version 1.9 
public interface Callback<T> {

  /** Successful HTTP response. */
  void success(T t, Response response);

  /**
   * Unsuccessful HTTP response due to network failure, non-2XX status code, or unexpected
   * exception.
   */
  void failure(RetrofitError error);
}
// Retrofit Callback Version 2.0	!!!!!!!!!
public interface Callback<T> {
  /** Successful HTTP response. */
  void onResponse(Response<T> response, Retrofit retrofit);

  /** Invoked when a network or unexpected exception occurred during the HTTP request. */
  void onFailure(Throwable t);
}
// OkHttp	
public interface Callback {
  void onFailure(Request request, IOException e);

  void onResponse(Response response) throws IOException; // 注意引數不同
}



/*********************************回顧一下Okhttp的呼叫方式********************************************/

//1. 建立 
OkHttpClient : OkHttpClient client = new OkHttpClient();
//2. 建立 
Request :  Request request = new Request.Builder()
									    .url("https://api.github.com/repos/square/okhttp/issues")
										.header("User-Agent", "OkHttp Headers.java")
										.addHeader("Accept", "application/json; q=0.5")
										.addHeader("Accept", "application/vnd.github.v3+json")
										.build();
												
//3. 使用 client 執行請求(兩種方式):  
//第一種,同步執行
Response response = client.newCall(request).execute();
// 第二種,非同步執行方式
client.newCall(request).enqueue(new Callback() { 
    @Override 
    public void onFailure(Request request, Throwable throwable) {
    // 複寫該方法
											 
    }
    @Override public void onResponse(Response response) throws IOException {
	// 複寫該方法
    }									   
}
	
	
/***********************************Retrofit 1.0 不能獲得 Header 或者整個 Body*****************************************/
/**********2.x 引入 Call , 每個Call只能呼叫一次,可以使用Clone方法來生成一次呼叫多次,使用Call既可以同步也可以非同步*********/

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call<List<Contributor>> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
}

Call<List<Contributor>> call =
    gitHubService.repoContributors("square", "retrofit");

response = call.execute(); /*************** 同步的方式呼叫,注意這裡返回了 Response 後面會提到 ********************/

// This will throw IllegalStateException: 每個Call只能執行一次
response = call.execute();

Call<List<Contributor>> call2 = call.clone(); // 呼叫Clone之後又可以執行
// This will not throw:
response = call2.execute();

/************************ 非同步的方式呼叫 *********************************/

Call<List<Contributor>> call =
    gitHubService.repoContributors("square", "retrofit");

call.enqueue(new Callback<List<Contributor>>() {
  @Override void onResponse(/* ... */) {
    // ...
  }

  @Override void onFailure(Throwable t) {
    // ...
  }
});

/****************************引入 Response,獲取返回的RawData,包括:response code, response message, headers**********************************/

class Response<T> {
  int code();
  String message();
  Headers headers();

  boolean isSuccess(); 
  T body();
  ResponseBody errorBody(); 
  com.squareup.okhttp.Response raw();
}

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call<List<Contributor>> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
} 

Call<List<Contributor>> call = 
    gitHubService.repoContributors("square", "retrofit");
Response<List<Contributor>> response = call.execute(); 

/*********************************** Dynamic URL *****************************************/

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call<List<Contributor>> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);

  @GET
  Call<List<Contributor>> repoContributorsPaginate(
      @Url String url);// 直接填入 URL 而不是在GET中替換欄位的方式
}

/*************************************根據返回值實現過載*****************************************************/
interface SomeService {
  @GET("/some/proto/endpoint")
  Call<SomeProtoResponse> someProtoEndpoint(); // SomeProtoResponse

  @GET("/some/json/endpoint")
  Call<SomeJsonResponse> someJsonEndpoint(); // SomeJsonResponse
}

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call<List<Contributor>> repoContributors(..);

  @GET("/repos/{owner}/{repo}/contributors")
  Observable<List<Contributor>> repoContributors2(..);

  @GET("/repos/{owner}/{repo}/contributors")
  Future<List<Contributor>> repoContributors3(..); // 可以返回 Future
}

/******************************************Retrofit 1.x Interceptor,新增頭部資訊的時候經常用到Interceptor*************************************************************/
    RestAdapter.Builder builder = new RestAdapter.Builder().setRequestInterceptor(new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            request.addHeader("Accept", "application/json;versions=1");
        }
    });


/******************************************Retrofit 2.x Interceptor**************************************************/            
    
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        
        Request request = original.newBuilder()
                                  .header("Accept", "application/json")
                                  .header("Authorization", "auth-token")
                                  .method(original.method(), original.body())
                                  .build();
       
       Response response = chain.proceed(request);
       return response;      
        
    }   
}

Retrofit retrofit = Retrofit.Builder()
            .baseUrl("https://your.api.url/v2/")
            .client(client).build();


/***************************************非同步例項*********************************************/
public interface APIService {

    @GET("/users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);

    @GET("/users/{user}/repos")
    Call<String> listReposStr(@Path("user") String user);
//錯誤,不能這樣使用非同步
//    @GET("/users/{user}/repos")
//    void listRepos(@Path("user") String user, Callback<List<Repo>> callback);
}

private void prepareServiceAPI() {
    //For logging
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);

    OkHttpClient client = new OkHttpClient();
    client.interceptors().add(new MyInterceptor());
    client.interceptors().add(logging);
	// setUp Retrofit 
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.github.com")
            //.addConverterFactory(new ToStringConverterFactory())
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();

    service = retrofit.create(APIService.class);
}
// 非同步呼叫
public void execute() {
    Call<List<Repo>> call = service.listRepos("pasha656");
    call.enqueue(new Callback<List<Repo>>() {
        @Override
        public void onResponse(Response<List<Repo>> response, Retrofit retrofit) {

            if (response.isSuccess()) {
                if (!response.body().isEmpty()) {
                    StringBuilder sb = new StringBuilder();
                    for (Repo r : response.body()) {
                        sb.append(r.getId()).append(" ").append(r.getName()).append(" \n");
                    }
                    activity.setText(sb.toString());
                }
            } else {
                APIError error = ErrorUtils.parseError(response, retrofit);
                Log.d("Pasha", "No succsess message "+error.getMessage());
            }


            if (response.errorBody() != null) {
                try {
                    Log.d("Pasha", "Error "+response.errorBody().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d("Pasha", "onFailure "+t.getMessage());
        }
    });
}

  

相關文章