okHttp

okHttp是square出的Http通訊Lib
目前有很多知名的Lib可以支援, 例如 Volley, Glide, Retrofit...

參考文件

ref link
okHttp http://square.github.io/okhttp/
github https://github.com/square/okhttp

如何使用

1.gradle

compile 'com.squareup.okhttp:okhttp:2.4.0'

2.Initial

建議只要new一個實體做全部的操作就行了

okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(30, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(30, TimeUnit.SECONDS);

3.GET

GET and POST 的用法主要的差別只有在Request而已

Request request = new Request.Builder()
      .url(url)
      .build();

4.POST

builde Requestbody

RequestBody formBody = new FormEncodingBuilder()
    .add("name", "Cuber")
    .add("age", "26")
    .build();

Request request = new Request.Builder()
      .url(url)
      .post(RequestBody)
      .build();

5.Send

把上面build出來的Request帶進來

Response response = client.newCall(request).execute();
//如果response回傳是null, 就代表timeout或 沒有網路

或是你想使用Callback...

Response response = client.newCall(request).enqueue(new Callback() {

    @Override
    public void onFailure(Request request, IOException e) {
        //timeout或 沒有網路 
        //注意!這裏是backgroundThread
    }

    @Override
        public void onResponse(Response response) throws IOException {
        //成功
        //注意!這裏是backgroundThread
    }
});

6.心得

我覺得okHttp最難寫的地方應該就是Callback了
相信很多人都會遇到,如果Callback回來之後,我的Activity finish了,或是我的Fragment replace了
此時更改UI,就會產生找不到View的問題

而且Callback回來,居然是在backgroundThread上,
這時候如果要操作View又要切換到mainThread去,略顯麻煩

所以我在寫的時候,是沒有使用Callback的 以下提供一種漂亮(自認...)的寫法給大家做參考

/* 以fragment為例 */

public class BaseFragment extends Fragment implements Handler.Callback {

private static final int MSG_QUERY_DATA = 0x00;
private static final int MSG_DISPLAY_DATA = 0x01;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    this.activity = activity;

    /* setup handler */
    HandlerThread handlerThread = new HandlerThread(getClass().getName());
    handlerThread.start();
    backgroundHandler = new Handler(handlerThread.getLooper(), this);
    uiHandler = new Handler(activity.getMainLooper(), this);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {

    /* start */
    backgroundHandler.sendEmptyMessage(MSG_QUERY_DATA);
}

@Override
public void onDestroyView() {

    /* 將Message清空,backgroundThread結束掉 */
    backgroundHandler.removeCallbacksAndMessages(null);
    uiHandler.removeCallbacksAndMessages(null);
    backgroundHandler.getLooper().quit();
    super.onDestroyView();
}

@Override
public boolean handleMessage(Message msg) {

    /* 如果fragment不在Activity上了,直接return掉,避免NPE */
    if (!isAdded()) return false;

    /* 做各種MSG */
    switch(msg.what){

        case MSG_QUERY_DATA:

            // do okHttp without callback
            Response response = client.newCall(request).execute();

            // 傳回 uiThread 做UI更新
            Message respMsg = uiHandler.obtainMessage();
            respMsg.what = MSG_DISPLAY_DATA;
            respMsg.obj = response;
            backgroundHandler.sendMessage(respMsg);
            break;

        case MSG_DISPLAY_DATA:

            Response apiResponse = (Response)msg.obj;

            // 失敗
            if(null == apiResponse){
                //show error
            }

            // 成功
            else{
               //display data on UI
            }

            break;

        return false;
    }
}

Interceptor

okHttp 的 Interceptor 就如同名稱「攔截器」一樣,攔截你的 Request 做一些你想做的事情再送出去。例如:

  1. 自動加上使用者目前使用的語言送出去取得對應語言的回傳內容。
  2. 將 Request 計算出這個 Request 的 sigunature 再附加上送出去。

在 okHttp 中分成 Application Interceptor 和 Network Interceptor 兩種。 Application Interceptor 是會可以被 cache 起來的。</br> 如官網的圖片: 圖解 interceptor

也就是在前面舉的 2 個例子中:

1.自動加上使用者目前使用的語言送出去取得對應語言的回傳內容

因為會根據不同參數的 Request 取回不同內容分別 cache,所以要使用 Application Interceptor 實作。

2.將 Request 計算出這個 Request 的 sigunature 再附加上送出去。

因為會每次 Request 只會根據不同時間計算出不同 sigunature,可是內容本身還是一樣的,所以要使用 Network Interceptor 實作。

Sample Code

如果今天要做計算 Request 的 sigunature ,則使用方式如下:

public class ApiClient {
    Interceptor signedRequestInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response response = null;
            try {
                Request originalRequest = chain.request();
                Request signedRequest = SignRequestUtil.signRequest(originalRequest);
                response = chain.proceed(signedRequest);
            } catch (NoSuchAlgorithmException | InvalidKeyException e) {
                 e.printStackTrace();
            }

            return response;
        }
    };

    OkHttpClient client = new OkHttpClient();
    client.networkInterceptors().add(signedRequestInterceptor);
}

public class SignRequestUtil {
    public static Request signRequest(Request originalRequest) {
        Request.Builder requestBuilder = originalRequest.newBuilder();

        // 在這做所有你需要做的事情,重新產生一個 Request 送出去。
        return requestBuilder
            .headers(getSignedHeaders(originalRequest))
            .build();
    }
}

results matching ""

    No results matching ""