Android -- OkHttp的简单使用和封装

BruArent 5年前
   <p>1, 昨天把okHttp仔细的看了一下,以前都是调用同事封装好了的网络框架,直接使用很容易,但自己封装却不是那么简单,还好,今天就来自我救赎一把,就和大家写写从最基础的OKHttp的简单get、post的使用,再到它的封装。</p>    <p>2, OkHttp的简单使用</p>    <p>首先我们创建一个工程,并在布局文件中添加三个控件,TextView(用于展示获取到json后的信息)、Button(点击开始请求网络)、ProgressBar(网络加载提示框)</p>    <p>①简单的异步Get请求</p>    <p>第一步,创建OKHttpClient对象</p>    <p>第二步,创建Request请求</p>    <p>第三步,创建一个Call对象</p>    <p>第四步,将请求添加到调度中</p>    <p>不多说,直接上代码:</p>    <pre>  <code class="language-java">//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);                          }                      });                    }              }            });</code></pre>    <p>效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5edb56709954fdcf1fd5f0afc076942a.gif"></p>    <p>注意,由于我们调用的enqueue()方法,是运行在网络线程中的,所以当我们得到json数据后想要获取更新UI的话,可以开使用handle.post()方法在run方法里面更新UI。</p>    <p>② 简单的异步Post请求</p>    <p>这里的Post请求我们以最常见的注册登录来举例。post请求的步骤和get是相似的只是在创建Request的 时候将服务器需要的参数传递进去.</p>    <p>代码如下 :</p>    <pre>  <code class="language-java">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());              }          });</code></pre>    <p>看一下我们服务器的断点</p>    <p><img src="https://simg.open-open.com/show/140e99048b194bdf0838640276fe1858.png"></p>    <p>可以看到我们服务器的确拿到了我们传递参数,再看一下我们请求后拿到的数据</p>    <p><img src="https://simg.open-open.com/show/cc86cb58dfc90f83d40e7598a7767fd3.png"></p>    <p>ok,这样的话我们的post方法就没什么问题了</p>    <p>3, OkHttp的封装</p>    <p>由于是封装我们可以吧OKHttp和Gson给结合起来,那么我们在gradle文件添加以下的依赖</p>    <pre>  <code class="language-java">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"</code></pre>    <p>①CallBack的创建</p>    <p>首选我们知道,当接口请求成功或者失败的时候我们需要将这个信息通知给用户,那么我们就需要创建一个抽象类RequestCallBack,请求前、成功、失败、请求后这几个方法,创建OnBefore()、OnAfter()、OnError()、OnResponse()对应</p>    <pre>  <code class="language-java">/**       * 在请求之前的方法,一般用于加载框展示       *       * @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);</code></pre>    <p>由于我们每次想要的数据不一定,所以这里我们用<T>来接收想要装成的数据格式,并通过反射得到想要的数据类型(一般是Bean、List)之类 ,所以RequestCallBack的整体代码如下:</p>    <pre>  <code class="language-java">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);  }</code></pre>    <p>②对Get、Post方法的简单封装</p>    <p>首先我们创建一个OkHttpClientManager类,由于是管理类,所以,单例加静态对象搞起</p>    <pre>  <code class="language-java">private static OkHttpClientManager mInstance;      public static OkHttpClientManager getInstance() {          if (mInstance == null){              synchronized (OkHttpClientManager.class) {                  if (mInstance == null) {                      mInstance = new OkHttpClientManager();                  }              }          }          return mInstance;      }</code></pre>    <p>在创建Manager对象的时候我们要把OkHttp的一些参数配置一下,顺便一提一下,由于我们我们异步get、post方法是运行在子线程中,所以这里我们添加了分发的 Handler mDelivery;,重写的OkHttpClientManager构造方法如下:</p>    <pre>  <code class="language-java">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();      }</code></pre>    <p>前面的外部调用对象封装好了,这里我们开始来封装Get或Post方法,我这里以Post方法为例子,首先分析一下,post方法会有几个参数,参数一url,参数二参数params,参数三Callback(及我们上面的RequestCallBack)参数四flag(用于取消请求操作,可为空),基础代码如下:</p>    <pre>  <code class="language-java">/**           * 通用基础的异步的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);          }</code></pre>    <p>那么我们再看一下deliveryResult方法到底是干什么的</p>    <pre>  <code class="language-java">/**       * 请求回调处理方法并传递返回值       * @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);                  }              }          });      }</code></pre>    <p>可以看到,这个方法主要是发出请求并对请求后的数据开始回调,这样我们就基本上封装好了一个post方法了  ,把代码这一部分的代码贴出来看看</p>    <pre>  <code class="language-java">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();          });      }  }</code></pre>    <p>这样我们就把Post方法封装好了,同理Get方法,ok,现在我们可以来调用调用了,在调用之前我们可以对返回数据格式再来封装封装,一般我们后台返回的数据格式是类似如下:</p>    <pre>  <code class="language-java">{   "code": 200,     "data": {},    "message": "登录成功"  }</code></pre>    <p>而data中有可能是对象,也有可能是数组,所以我们用两个类来实现一下</p>    <p>CommonResultBean</p>    <pre>  <code class="language-java">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;      }  }</code></pre>    <p>CommonResultListBean</p>    <pre>  <code class="language-java">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;      }  }</code></pre>    <p>ok,现在还是以上面我们登录的接口为例子开始我们的方法调用,返回的数据格式如图所示</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/69ca3ef977d4cf9e275ca977381dc5ff.png"></p>    <p>我们创建UserMenu.java类</p>    <pre>  <code class="language-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;          }      }    }</code></pre>    <p>所以MainActivity代码如下:</p>    <pre>  <code class="language-java">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);                          }                      }                  });        }  }</code></pre>    <p>这样我们就可以简单的调用了,最后看一下我们的效果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/1eec3f848cea1ba8e70c6142a01d57da.gif"></p>    <p>See You Next Time···</p>    <p> </p>    <p>来自:http://www.cnblogs.com/wjtaigwh/p/6210534.html</p>    <p> </p>