1. 程式人生 > >okHttp簡單封裝使用

okHttp簡單封裝使用

最近一個專案在使用okhttp 這裡記錄一下使用過程,關於okhttp的使用網上已經有很多講解,下面說一下本人在專案中使用過程中對其進行的簡單封裝

直接進入主題

使用okhttp首先要在gradle.build裡面加入  

compile 'com.squareup.okhttp:okhttp:2.6.0'

我定義了一個介面api規範一下我的請求函式

import android.content.Context;


/**
 * Created by lkk on 2016/5/10.
 */
public interface Api {
   
<span style="white-space:pre">	</span>// API域名
    public static final String API_BASE_DOCTOR = "";// 
    /**
     * 登陸
     *
     * @param context
     * @param vCode   驗證碼
     * @param phone   手機號
     */
    void login(Context context, String vCode, String phone, ResultCallback callback);


    /**
     * 傳送驗證碼
     *
     * @param context
     * @param phone   手機號
     */
    void sendCode(Context context, String phone, ResultCallback callback);

}
這裡簡單定義了兩個請求,  Context引數是因為後面提取header資訊要用到, ResultCallback用來回調通知請求結果看程式碼
import com.google.gson.internal.$Gson$Types;
import com.squareup.okhttp.Request;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Created by Administrator on 2015/12/5 0005.
 * <p/>
 * 回撥函式
 * 請求事件結果通知
 */
public abstract class ResultCallback<T> {

    public Type mType;

    public ResultCallback() {

        mType = getSuperclassTypeParameter(getClass());
    }

    Type getSuperclassTypeParameter(Class<?> subclass) {

        Type superclass = subclass.getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new RuntimeException("Missing type parameter.");
        }
        ParameterizedType parameterized = (ParameterizedType) superclass;
        return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
    }

    /**
     * 網路請求失敗
     *
     * @param request
     * @param e
     */
    public void onFailure(Request request, Exception e) {
    }

    /**
     * 網路請求錯誤
     *
     * @param code
     * @param message
     */
    public void onError(int code, String message) {
    }

    /**
     * 請求伺服器成功
     *
     * @param response
     */
    public void onResponse(T response) {
    }

    /**
     * 請求完成
     */
    public void onFinish() {
    }

    /**
     * 請求開始
     */
    public void onStart() {
    }

}
mType是拿到資料gson解析成的物件型別,有了它string變物件模型就easy了,這裡我定義了 onStart和onFinish回撥函式是因為我要在這裡處理progressDialog

 下面是我定義的一個抽象類來收集請求引數資料

import android.content.Context;

import com.squareup.okhttp.Request;

import java.util.TreeMap;


/**
 * Created by lkk on 2016/5/10.
 *  代理操作  收集請求資料
 *  呼叫實現
 */
public abstract class AbsGateway implements Api {

    /** 登入 */
    String API_LOGIN = "";
    /**傳送驗證碼*/
    private static final String API_SEND_CODE = "";

    private static AbsGateway mInstance;

    public static AbsGateway getInstance() {
        synchronized (AbsGateway.class){
            if (mInstance == null) {
                mInstance = new GatewayImp();
            }
        }
        return mInstance;
    }


    @Override
    public void login(Context context, String vCode, String phone, ResultCallback callback) {
        TreeMap<String, String> mParam = new TreeMap<String, String>();
        mParam.put("verify_code", vCode);
        mParam.put("phone", phone);
        deliveryResult(context, callback, getOrderParamString(context, API_LOGIN, mParam));
    }

    @Override
    public void sendCode(Context context, String phone, ResultCallback callback) {
        TreeMap<String, String> mParam = new TreeMap<String, String>();
        mParam.put("phone", phone);
        deliveryResult(context, callback, getOrderParamString(context, API_SEND_CODE, mParam));
    }

    /**
     * 發出請求 以及處理返回結果執行回撥
     * @param cxt
     * @param callback
     * @param request
     */
    abstract void deliveryResult(Context cxt, ResultCallback callback, Request request);

    /**
     * 引數 排序加密處理
     * @param context
     * @param url 介面地址(不包含域名)
     * @param mParam 引數集合
     * @return 返回Request物件
     */
    abstract Request getOrderParamString(Context context, String url, TreeMap mParam);
}
這裡定義了我的介面地址和介面請求回撥上面兩個抽象函式註釋已經很明確了就不介紹了, 由於加密前需要對引數進行字母表順序排序所以我用了TreeMap進行儲存

再來看下面的實現類

import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.widget.Toast;

import com.google.gson.Gson;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.util.Iterator;
import java.util.TreeMap;



/**
 * Created by lkk on 2016/5/10.
 *
 * 實現發起網路請求事件
 * 實現請求資料排序加密操作
 * 處理網路請求返回的資料
 * 執行回撥事件
 */
public class GatewayImp extends AbsGateway{

   

    protected OkHttpClient client = new OkHttpClient();

    public Handler mHandle;
    public Gson mGson;

    public GatewayImp() {
        client = new OkHttpClient();
        //cookie enabled
        client.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
        mHandle = new Handler(Looper.getMainLooper());
        mGson = new Gson();
    }

    @Override
    void deliveryResult(final Context cxt, final ResultCallback callback, Request request) {
        if (!SystemInfo.isNetworkConnected(cxt)) {
            Toast.makeText(cxt,
                    cxt.getString(R.string.toast_not_network), Toast.LENGTH_SHORT).show();
            return;
        }
        if (callback != null) {
            callback.onStart();
        }
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                
                onFailuerMessage(callback, request, e);
            }

            @Override
            public void onResponse(final Response response) {
                try {
                   
                    if (response.code() != 200) {
                        onErrorMessage(callback, response.code(), response.message());
                        return;
                    }
                    String str = response.body().string().toString();
                   
                    if (!TextUtils.isEmpty(str.trim())) {
                        Result mResult = mGson.fromJson(str, callback.mType);
                        parse(cxt, callback, mResult);
                    }
                } catch (Exception e) {
                    LogInfo.e("parse exception is: " + e.toString());
                }
            }
        });
    }

    @Override
    Request getOrderParamString(Context context, String url, TreeMap mParam) {
        FormEncodingBuilder builder = new FormEncodingBuilder();
        String timestamp = String.valueOf(System.currentTimeMillis());
        String uuid = SystemInfo.getIMEI(context);//獲取IMEI
        String version = PackageUtils.getAppVersion(context);//這裡獲取版本號
        String app_key = "加密協議字串";
        Iterator<String> iter = mParam.keySet().iterator();
        String key;
        while (iter.hasNext()) {
            key = iter.next();
            builder.add(key, String.valueOf(mParam.get(key)));
        }
        String paramsStr = URLEncodedUtils.format(mParam, HTTP.UTF_8);
        String signature = Tools.getMD5(Config.PLATFORM + app_key + uuid + version + paramsStr + timestamp);
        
        return buildRequest(context, builder, API_BASE_DOCTOR + url, version, uuid, signature, timestamp);
    }


    /**
     * <br>post非同步請求<br>
     * 獲取請求頭資訊
     *
     * @param url
     * @return
     */
    private Request buildRequest(Context cxt, FormEncodingBuilder builder, String url, String version, String uuid, String signature, String timestamp) {
        Request request = new Request.Builder()
                .url(url)
                .header("User-Agent", "OkHttp Headers.java")
                .addHeader("Accept", "application/json; q=0.5")
                .addHeader("Accept", "application/vnd.github.v3+json")
                .addHeader("X-VERSION", version)
                .addHeader("X-VerName", version)
                .addHeader("X-VerCode", version)
                .addHeader("X-Platform", Config.PLATFORM)
                .addHeader("X-Device", Build.DEVICE)
                .addHeader("X-Uuid", uuid)
                .addHeader("X-BuildVersion", Build.VERSION.RELEASE)
                .addHeader("timestamp", timestamp)
                .addHeader("signature", signature)
                .post(builder.build())
                .build();
        return request;
    }

    /**
     * 伺服器沒有響應
     *
     * @param callback
     * @param request
     * @param e
     */
    private void onFailuerMessage(final ResultCallback callback, final Request request, final IOException e) {
        mHandle.post(new Runnable() {
            @Override
            public void run() {
                callback.onFailure(request, e);
                callback.onFinish();
            }
        });
    }


    /**
     * 伺服器沒有響應
     *
     * @param callback
     * @param code
     * @param message
     */
    private void onErrorMessage(final ResultCallback callback, final int code, final String message) {
        mHandle.post(new Runnable() {
            @Override
            public void run() {
                callback.onError(code, message);
                callback.onFinish();
            }
        });
    }

    /**
     * 解析資料
     * 轉成主執行緒回撥
     *
     * @param callback
     * @param mResult
     */
    private void parse(final Context cxt, final ResultCallback callback, final Result mResult) {
        mHandle.post(new Runnable() {
            @Override
            public void run() {
               
                if (mResult.getCode() == 1) {
                    callback.onResponse(mResult);
                   
                } else {
                    callback.onResponse(mResult.getCode(), mResult.getMsg());
                   
                }<pre name="code" class="java"><span style="white-space:pre">		</span>callback.onFinish();
} }); } 該類完成了父類定義的兩個抽象類的實現 , 後面再新增介面這裡就不用改動的

deliveryResult  執行我的okhttp請求 並對請求回來的資料進行解析,  callback.mType 就是前面提到的資料物件型別

getOrederParamString 完成引數加密邏輯

buildRequest  新增頭資訊引數

parse     請求成功拿到資料 進行回撥, 由於okHttp已經處理好了非同步請求,包含回撥也是非同步這裡我用了一個handle當作主執行緒回撥

該實現類完成之後後面增加請求介面只需在api裡面定義,  在抽象類裡呼叫就ok了, 

請求時這樣呼叫:

  private void reqLogin(){

        AbsGateway.getInstance().login(this, "", "", callback);
    }
    
    ResultCallback callback = new ResultCallback<User>(){

        @Override
        public void onStart() {
            //顯示 progressDialog
        }

        @Override
        public void onResponse(User response) {
<span style="white-space:pre">		</span>//請求到資料
        }

        @Override
        public void onFinish() {
            // 關閉 progressDialog
        }
    };

注: 這裡只是實現了okHttp的post請求, 還有get請求和HTTP方式檔案上傳 , 好像android4.4原始碼裡HttpURLConnection已經被okHttp替代了更說明了它的潛力