Android OkHttp的简单使用和封装详解
android okhttp的简单使用和封装详解
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···
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!