1. 程式人生 > >網路請求工具類之OkHttp3封裝(二)下(支援請求取消、非同步請求的執行緒切換)

網路請求工具類之OkHttp3封裝(二)下(支援請求取消、非同步請求的執行緒切換)

緊接著上篇說的任務2:非同步請求採用UI執行緒回撥方式。

首先採用Handler進行執行緒間的通訊,順便優化下回調方法,加入HttpInfo以做到工具類使用的滲透性。

在OkHttpUtil中宣告一個自定義的非同步回撥介面,該介面對網路請求介面進行了封裝,使同步、非同步請求處理流程保持一致性,程式碼如下:

/**
     * 非同步請求回撥介面
     */
    public interface CallbackOk {
        /**
         * 該回調方法已切換到UI執行緒
         */
        void onResponse(HttpInfo info) throws IOException;
    }

在OkHttpUtil中增加Handler業務排程程式碼:

private final static int WHAT_CALLBACK = 1;
/**
     * 主執行緒業務排程
     */
    private static Handler handler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(Message msg) {
            final int what = msg.what;
            switch (what){
                case WHAT_CALLBACK:
                    try {
                        CallbackMessage callMsg = (CallbackMessage) msg.obj;
                        callMsg.callback.onResponse(callMsg.info);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    break;
            }
        }
    };

修改OkHttpUtil中非同步請求方法:

 /**
     * 非同步請求
     * @param info
     * @param method
     * @param callback
     */
    private void doRequestAsync(HttpInfo info, Method method, CallbackOk callback){
        if(null == callback)
            throw new NullPointerException("CallbackOk is null that not allowed");
        Call call = httpClient.newCall(fetchRequest(info,method));
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                showLog(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response res) throws IOException {
                //主執行緒回撥
                handler.sendMessage(new CallbackMessage(WHAT_CALLBACK,callback,dealResponse(info,res)).build());
            }
        });
        putCall(info,call);
    }

這樣邏輯應該很清晰了,非同步請求後通知Handler進行回撥,Handler負責執行緒的通訊(即回撥),這裡CallbackMessage是對Messay進行了包裹,增加了CallbackOk與HttpInfo屬性。

/**
     * 回撥資訊實體類
     */
    public class CallbackMessage{
        public int what;
        public CallbackOk callback;
        public HttpInfo info;
        public CallbackMessage(int what, CallbackOk callback, HttpInfo info) {
            this.what = what;
            this.callback = callback;
            this.info = info;
        }
        public Message build(){
            Message msg = new Message();
            msg.what = this.what;
            msg.obj = this;
            return msg;
        }
    }
這裡對網路請求方法進行了自定義的封裝處理:
private HttpInfo dealResponse(HttpInfo info, Response res){
        try {
            if(null != res && null != res.body()){
                if(res.isSuccessful()){
                    return retInfo(info,info.SUCCESS,res.body().string());
                }else{
                    showLog("HttpStatus: "+res.code());
                    if(res.code() == 404)//請求頁面路徑錯誤
                        return retInfo(info,info.CheckURL);
                    if(res.code() == 500)//伺服器內部錯誤
                        return retInfo(info,info.NoResult);
                    if(res.code() == 502)//錯誤閘道器
                        return retInfo(info,info.CheckNet);
                    if(res.code() == 504)//閘道器超時
                        return retInfo(info,info.CheckNet);
                }
            }
            return retInfo(info,info.CheckURL);
        } catch (Exception e) {
            return retInfo(info,info.NoResult);
        }
    }

下面我們來看下Activity/Fragment的非同步網路請求程式碼:

 private void doHttpAsync() {
        OkHttpUtil.Builder().build().doGetAsync(HttpInfo.Builder().setUrl(url).build(this), info ->  {
            if (info.isSuccessful()) {
                String ret = info.getRetDetail();
                tv_content.setText(ret);
            }
        });
    }

可以看出onResponse回撥方法已經是在UI執行緒了,可以盡情修改介面,再也不用runOnUIThread包裹,這裡採用了Lambda表示式,程式碼看起來是不是清爽多了。

專案已上傳至GitHub:https://github.com/MrZhousf/OkHttp3