Android -- OkHttp的簡單使用和封裝

BruArent 8年前發布 | 17K 次閱讀 OkHttp 安卓開發 Android開發 移動開發

1, 昨天把okHttp仔細的看了一下,以前都是調用同事封裝好了的網絡框架,直接使用很容易,但自己封裝卻不是那么簡單,還好,今天就來自我救贖一把,就和大家寫寫從最基礎的OKHttp的簡單get、post的使用,再到它的封裝。

2, OkHttp的簡單使用

首先我們創建一個工程,并在布局文件中添加三個控件,TextView(用于展示獲取到json后的信息)、Button(點擊開始請求網絡)、ProgressBar(網絡加載提示框)

①簡單的異步Get請求

第一步,創建OKHttpClient對象

第二步,創建Request請求

第三步,創建一個Call對象

第四步,將請求添加到調度中

不多說,直接上代碼:

//okHttp的基本使用 --- get方法
        String url = "https://api.douban.com/v2/movie/top250?start=0&count=10";
        //1,創建OKHttpClient對象
        OkHttpClient mOkHttpClient = new OkHttpClient();
        //2,創建一個Request
        Request request = new Request.Builder().url(url).build();
        //3,創建一個call對象
        Call call = mOkHttpClient.newCall(request);
        //4,將請求添加到調度中
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {

            }

            @Override
            public void onResponse(Response response) throws IOException {
                if (response.isSuccessful()) {
                    final String message = response.body().string();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            tv_message.setText(message);
                            progressBar.setVisibility(View.GONE);
                        }
                    });

                }
            }

        });

效果如下:

注意,由于我們調用的enqueue()方法,是運行在網絡線程中的,所以當我們得到json數據后想要獲取更新UI的話,可以開使用handle.post()方法在run方法里面更新UI。

② 簡單的異步Post請求

這里的Post請求我們以最常見的注冊登錄來舉例。post請求的步驟和get是相似的只是在創建Request的 時候將服務器需要的參數傳遞進去.

代碼如下 :

String url = "http://192.168.1.123:8081/api/login";
        //1,創建OKhttpClient對象
        OkHttpClient mOkHttpClient = new OkHttpClient();
        //2,創建Request
        RequestBody formBody = new FormEncodingBuilder()
                .add("username", "superadmin")
                .add("pwd", "ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413")
                .build();

        Request request = new Request.Builder().url(url).post(formBody).build();
        //3,創建call對象并將請求對象添加到調度中
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {

            }

            @Override
            public void onResponse(Response response) throws IOException {
                Log.i("wangjitao", response.body().string());
            }
        });

看一下我們服務器的斷點

可以看到我們服務器的確拿到了我們傳遞參數,再看一下我們請求后拿到的數據

ok,這樣的話我們的post方法就沒什么問題了

3, OkHttp的封裝

由于是封裝我們可以吧OKHttp和Gson給結合起來,那么我們在gradle文件添加以下的依賴

compile "com.squareup.okhttp:okhttp:2.4.0"
 compile 'com.squareup.okio:okio:1.5.0'
 compile "com.google.code.gson:gson:2.8.0"

①CallBack的創建

首選我們知道,當接口請求成功或者失敗的時候我們需要將這個信息通知給用戶,那么我們就需要創建一個抽象類RequestCallBack,請求前、成功、失敗、請求后這幾個方法,創建OnBefore()、OnAfter()、OnError()、OnResponse()對應

/**
     * 在請求之前的方法,一般用于加載框展示
     *
     * @param request
     */
    public void onBefore(Request request) {
    }

    /**
     * 在請求之后的方法,一般用于加載框隱藏
     */
    public void onAfter() {
    }

    /**
     * 請求失敗的時候
     *
     * @param request
     * @param e
     */
    public abstract void onError(Request request, Exception e);

    /**
     *
     * @param response
     */
    public abstract void onResponse(T response);

由于我們每次想要的數據不一定,所以這里我們用<T>來接收想要裝成的數據格式,并通過反射得到想要的數據類型(一般是Bean、List)之類 ,所以RequestCallBack的整體代碼如下:

package com.qianmo.httprequest.http;

import com.google.gson.internal.$Gson$Types;
import com.squareup.okhttp.Request;

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


/**
 * Created by wangjitao on 15/10/16.
 * 抽象類,用于請求成功后的回調
 */
public abstract class ResultCallback<T> {
    //這是請求數據的返回類型,包含常見的(Bean,List等)
    Type mType;

    public ResultCallback() {
        mType = getSuperclassTypeParameter(getClass());
    }

    /**
     * 通過反射想要的返回類型
     *
     * @param subclass
     * @return
     */
    static 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
     */
    public void onBefore(Request request) {
    }

    /**
     * 在請求之后的方法,一般用于加載框隱藏
     */
    public void onAfter() {
    }

    /**
     * 請求失敗的時候
     *
     * @param request
     * @param e
     */
    public abstract void onError(Request request, Exception e);

    /**
     *
     * @param response
     */
    public abstract void onResponse(T response);
}

②對Get、Post方法的簡單封裝

首先我們創建一個OkHttpClientManager類,由于是管理類,所以,單例加靜態對象搞起

private static OkHttpClientManager mInstance;

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

在創建Manager對象的時候我們要把OkHttp的一些參數配置一下,順便一提一下,由于我們我們異步get、post方法是運行在子線程中,所以這里我們添加了分發的 Handler mDelivery;,重寫的OkHttpClientManager構造方法如下:

private OkHttpClientManager() {
        mOkHttpClient = new OkHttpClient();
        mOkHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
        mOkHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);
        mOkHttpClient.setReadTimeout(30, TimeUnit.SECONDS);
        //cookie enabled
        mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
        mDelivery = new Handler(Looper.getMainLooper());
        mGson = new Gson();
    }

前面的外部調用對象封裝好了,這里我們開始來封裝Get或Post方法,我這里以Post方法為例子,首先分析一下,post方法會有幾個參數,參數一url,參數二參數params,參數三Callback(及我們上面的RequestCallBack)參數四flag(用于取消請求操作,可為空),基礎代碼如下:

/**
         * 通用基礎的異步的post請求
         * @param url
         * @param callback
         * @param tag
         */
        public void postAsyn(String url, Param[] params, final ResultCallback callback, Object tag) {
            Request request = buildPostFormRequest(url, params, tag);
            deliveryResult(callback, request);
        }

那么我們再看一下deliveryResult方法到底是干什么的

/**
     * 請求回調處理方法并傳遞返回值
     * @param callback Map類型請求參數
     * @param request Request請求
     */
    private void deliveryResult(ResultCallback callback, Request request) {
        if (callback == null)
            callback = DEFAULT_RESULT_CALLBACK;
        final ResultCallback resCallBack = callback;
        //UI thread
        callback.onBefore(request);
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                sendFailedStringCallback(request, e, resCallBack);
            }

            @Override
            public void onResponse(final Response response) {
                try {
                    final String responseMessage=response.message();
                    final String responseBody = response.body().string();
                    if(response.code()==200){
                        if (resCallBack.mType == String.class) {
                            sendSuccessResultCallback(responseBody, resCallBack);
                        } else {
                            Object o = mGson.fromJson(responseBody, resCallBack.mType);
                            sendSuccessResultCallback(o, resCallBack);
                        }
                    }else{
                        Exception exception=new Exception(response.code()+":"+responseMessage);
                        sendFailedStringCallback(response.request(), exception, resCallBack);
                    }
                } catch (IOException e) {
                    sendFailedStringCallback(response.request(), e, resCallBack);
                } catch (com.google.gson.JsonParseException e) {//Json解析的錯誤
                    sendFailedStringCallback(response.request(), e, resCallBack);
                }
            }
        });
    }

可以看到,這個方法主要是發出請求并對請求后的數據開始回調,這樣我們就基本上封裝好了一個post方法了  ,把代碼這一部分的代碼貼出來看看

public class OkHttpClientManager {
    private static final String TAG = "com.qianmo.httprequest.http.OkHttpClientManager";

    private static OkHttpClientManager mInstance;
    //默認的請求回調類
    private final ResultCallback<String> DEFAULT_RESULT_CALLBACK = new ResultCallback<String>(){
        @Override
        public void onError(Request request, Exception e) {}

        @Override
        public void onResponse(String response) {}
    };
    private OkHttpClient mOkHttpClient;
    private Handler mDelivery;
    private Gson mGson;
    private GetDelegate mGetDelegate = new GetDelegate();
    private PostDelegate mPostDelegate = new PostDelegate();
    private DownloadDelegate mDownloadDelegate = new DownloadDelegate();

    private OkHttpClientManager() {
        mOkHttpClient = new OkHttpClient();
        mOkHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
        mOkHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);
        mOkHttpClient.setReadTimeout(30, TimeUnit.SECONDS);
        //cookie enabled
        mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
        mDelivery = new Handler(Looper.getMainLooper());
        mGson = new Gson();
    }

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

    /**
     * 外部可調用的Post異步請求方法
     * @param url 請求url
     * @param params
     * @param callback 請求完成后回調類
     */
    public static void postAsyn(String url, Map<String, String> params, final ResultCallback callback) {
        getInstance().getPostDelegate().postAsyn(url, params, callback, null);
    }

    /**
         * 異步的post請求
         * @param url
         * @param params
         * @param callback
         * @param tag
         */
        public void postAsyn(String url, Map<String, String> params, final ResultCallback callback, Object tag) {
            Param[] paramsArr = map2Params(params);
            postAsyn(url, paramsArr, callback, tag);
        }
    /**
         * 通用基礎的異步的post請求
         * @param url
         * @param callback
         * @param tag
         */
        public void postAsyn(String url, Param[] params, final ResultCallback callback, Object tag) {
            Request request = buildPostFormRequest(url, params, tag);
            deliveryResult(callback, request);
        }

    /**
     * 請求回調處理方法并傳遞返回值
     * @param callback Map類型請求參數
     * @param request Request請求
     */
    private void deliveryResult(ResultCallback callback, Request request) {
        if (callback == null)
            callback = DEFAULT_RESULT_CALLBACK;
        final ResultCallback resCallBack = callback;
        //UI thread
        callback.onBefore(request);
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                sendFailedStringCallback(request, e, resCallBack);
            }

            @Override
            public void onResponse(final Response response) {
                try {
                    final String responseMessage=response.message();
                    final String responseBody = response.body().string();
                    if(response.code()==200){
                        if (resCallBack.mType == String.class) {
                            sendSuccessResultCallback(responseBody, resCallBack);
                        } else {
                            Object o = mGson.fromJson(responseBody, resCallBack.mType);
                            sendSuccessResultCallback(o, resCallBack);
                        }
                    }else{
                        Exception exception=new Exception(response.code()+":"+responseMessage);
                        sendFailedStringCallback(response.request(), exception, resCallBack);
                    }
                } catch (IOException e) {
                    sendFailedStringCallback(response.request(), e, resCallBack);
                } catch (com.google.gson.JsonParseException e) {//Json解析的錯誤
                    sendFailedStringCallback(response.request(), e, resCallBack);
                }
            }
        });
    }
     /**
     * 處理請求成功的回調信息方法
     * @param object 服務器響應信息
     * @param callback 回調類
     */
    private void sendSuccessResultCallback(final Object object, final      ResultCallback callback) {
        mDelivery.post(() -> {
            callback.onResponse(object);
            callback.onAfter();
        });
    }
}

這樣我們就把Post方法封裝好了,同理Get方法,ok,現在我們可以來調用調用了,在調用之前我們可以對返回數據格式再來封裝封裝,一般我們后臺返回的數據格式是類似如下:

{
 "code": 200, 
  "data": {}, 
 "message": "登錄成功"
}

而data中有可能是對象,也有可能是數組,所以我們用兩個類來實現一下

CommonResultBean

package com.qianmo.httprequest.bean;

/**
 * 服務端返回通用接收實體
 * Created by wangjitao on 15/10/30.
 */
public class CommonResultBean<T> {
    private String code;
    private T data;
    private String message;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

CommonResultListBean

package com.qianmo.httprequest.bean;

import java.util.List;

/**
 * 服務端返回帶有List數據的通用接收實體
 * Created by wangjitao on 15/12/1.
 */
public class CommonResultListBean<T> {
    private String code;
    private List<T> data;
    private String message;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

ok,現在還是以上面我們登錄的接口為例子開始我們的方法調用,返回的數據格式如圖所示

我們創建UserMenu.java類

package com.qianmo.httprequest.bean;

import java.util.List;

/**
 * Created by wangjitao on 2016/12/21 0021.
 * E-Mail:543441727@qq.com
 * 用戶菜單權限按鈕
 */
public class UserMenu {

    /**
     * last_login_time : 2016-12-21 15:40:28
     * member_id : 1
     * modules : []
     * phone : 18900532225
     * real_name : 超級管理員
     * role : {"role_id":1,"role_name":"超級管理員"}
     * username : superadmin
     */

    private String last_login_time;
    private int member_id;
    private String phone;
    private String real_name;
    /**
     * role_id : 1
     * role_name : 超級管理員
     */

    private RoleBean role;
    private String username;
    /**
     * module_code : 100
     * module_id : 1
     * module_name : 首頁
     * pid : 0
     * type : 1
     * value : P_index
     */

    private List<ModulesBean> modules;

    public String getLast_login_time() {
        return last_login_time;
    }

    public void setLast_login_time(String last_login_time) {
        this.last_login_time = last_login_time;
    }

    public int getMember_id() {
        return member_id;
    }

    public void setMember_id(int member_id) {
        this.member_id = member_id;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getReal_name() {
        return real_name;
    }

    public void setReal_name(String real_name) {
        this.real_name = real_name;
    }

    public RoleBean getRole() {
        return role;
    }

    public void setRole(RoleBean role) {
        this.role = role;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public List<ModulesBean> getModules() {
        return modules;
    }

    public void setModules(List<ModulesBean> modules) {
        this.modules = modules;
    }

    public static class RoleBean {
        private int role_id;
        private String role_name;

        public int getRole_id() {
            return role_id;
        }

        public void setRole_id(int role_id) {
            this.role_id = role_id;
        }

        public String getRole_name() {
            return role_name;
        }

        public void setRole_name(String role_name) {
            this.role_name = role_name;
        }
    }

    public static class ModulesBean {
        private String module_code;
        private int module_id;
        private String module_name;
        private int pid;
        private int type;
        private String value;

        public String getModule_code() {
            return module_code;
        }

        public void setModule_code(String module_code) {
            this.module_code = module_code;
        }

        public int getModule_id() {
            return module_id;
        }

        public void setModule_id(int module_id) {
            this.module_id = module_id;
        }

        public String getModule_name() {
            return module_name;
        }

        public void setModule_name(String module_name) {
            this.module_name = module_name;
        }

        public int getPid() {
            return pid;
        }

        public void setPid(int pid) {
            this.pid = pid;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

}

所以MainActivity代碼如下:

package com.qianmo.httprequest;

import android.os.Environment;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.qianmo.httprequest.bean.CommonResultBean;
import com.qianmo.httprequest.bean.UserMenu;
import com.qianmo.httprequest.http.IRequestCallBack;
import com.qianmo.httprequest.http.IRequestManager;
import com.qianmo.httprequest.http.OkHttpClientManager;
import com.qianmo.httprequest.http.RequestFactory;
import com.qianmo.httprequest.http.ResultCallback;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


public class MainActivity extends AppCompatActivity implements OnClickListener {
    private Handler handler;
    private TextView tv_message;
    private Button btn_login;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_message = (TextView) findViewById(R.id.tv_message);
        btn_login = (Button) findViewById(R.id.btn_login);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        handler = new Handler();
        btn_login.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        progressBar.setVisibility(View.VISIBLE);


        String url = "http://192.168.1.123:8081/api/login";
        Map<String, String> params = new HashMap();
        params.put("username", "superadmin");
        params.put("pwd", "ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413");
        OkHttpClientManager.postAsyn(url, params,
                new ResultCallback<CommonResultBean<UserMenu>>() {
                    @Override
                    public void onError(Request request, Exception e) {

                    }

                    @Override
                    public void onResponse(CommonResultBean<UserMenu> response) {
                        if (response.getData() != null) {
                            UserMenu userMenu = response.getData();
                            tv_message.setText(userMenu.getReal_name());
                            progressBar.setVisibility(View.GONE);
                        }
                    }
                });

    }
}

這樣我們就可以簡單的調用了,最后看一下我們的效果:

See You Next Time···

 

來自:http://www.cnblogs.com/wjtaigwh/p/6210534.html

 

 本文由用戶 BruArent 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!