Android--OkHttp的简单使用和封装
1,昨天把okHttp仔细的看了一下,以前都是调用同事封装好了的网络框架,直接使用很容易,但自己封装却不是那么简单,还好,今天就来自我救赎一把,就和大家写写从最基础的OKHttp的简单get、post的使用,再到它的封装。
2,OkHttp的简单使用
首先我们创建一个工程,并在布局文件中添加三个控件,TextView(用于展示获取到json后的信息)、Button(点击开始请求网络)、ProgressBar(网络加载提示框)
①简单的异步Get请求
第一步,创建OKHttpClient对象
第二步,创建Request请求
第三步,创建一个Call对象
第四步,将请求添加到调度中
不多说,直接上代码:
//okHttp的基本使用---get方法
Stringurl="https://api.douban.com/v2/movie/top250?start=0&count=10";
//1,创建OKHttpClient对象
OkHttpClientmOkHttpClient=newOkHttpClient();
//2,创建一个Request
Requestrequest=newRequest.Builder().url(url).build();
//3,创建一个call对象
Callcall=mOkHttpClient.newCall(request);
//4,将请求添加到调度中
call.enqueue(newCallback(){
@Override
publicvoidonFailure(Requestrequest,IOExceptione){
}
@Override
publicvoidonResponse(Responseresponse)throwsIOException{
if(response.isSuccessful()){
finalStringmessage=response.body().string();
handler.post(newRunnable(){
@Override
publicvoidrun(){
tv_message.setText(message);
progressBar.setVisibility(View.GONE);
}
});
}
注意,由于我们调用的enqueue()方法,是运行在网络线程中的,所以当我们得到json数据后想要获取更新UI的话,可以开使用handle.post()方法在run方法里面更新UI。
②简单的异步Post请求
这里的Post请求我们以最常见的注册登录来举例。post请求的步骤和get是相似的只是在创建Request的时候将服务器需要的参数传递进去.
代码如下:
Stringurl="http://192.168.1.123:8081/api/login";
//1,创建OKhttpClient对象
OkHttpClientmOkHttpClient=newOkHttpClient();
//2,创建Request
RequestBodyformBody=newFormEncodingBuilder()
.add("username","superadmin")
.add("pwd","ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413")
.build();
Requestrequest=newRequest.Builder().url(url).post(formBody).build();
//3,创建call对象并将请求对象添加到调度中
mOkHttpClient.newCall(request).enqueue(newCallback(){
@Override
publicvoidonFailure(Requestrequest,IOExceptione){
}
@Override
publicvoidonResponse(Responseresponse)throwsIOException{
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()对应
/
在请求之前的方法,一般用于加载框展示
@paramrequest
/
publicvoidonBefore(Requestrequest){
}
/
在请求之后的方法,一般用于加载框隐藏
/
publicvoidonAfter(){
}
/
请求失败的时候
@paramrequest
@parame
/
publicabstractvoidonError(Requestrequest,Exceptione);
/
@paramresponse
/
publicabstractvoidonResponse(Tresponse);
由于我们每次想要的数据不一定,所以这里我们用来接收想要装成的数据格式,并通过反射得到想要的数据类型(一般是Bean、List)之类,所以RequestCallBack的整体代码如下:
packagecom.qianmo.httprequest.http;
importcom.google.gson.internal.$Gson$Types;
importcom.squareup.okhttp.Request;
importjava.lang.reflect.ParameterizedType;
importjava.lang.reflect.Type;
/
Createdbywangjitaoon15/10/16.
抽象类,用于请求成功后的回调
/
publicabstractclassResultCallback{
//这是请求数据的返回类型,包含常见的(Bean,List等)
TypemType;
publicResultCallback(){
mType=getSuperclassTypeParameter(getClass());
}
/
通过反射想要的返回类型
@paramsubclass
@return
/
staticTypegetSuperclassTypeParameter(Class>subclass){
Typesuperclass=subclass.getGenericSuperclass();
if(superclassinstanceofClass){
thrownewRuntimeException("Missingtypeparameter.");
}
ParameterizedTypeparameterized=(ParameterizedType)superclass;
return$Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
/
在请求之前的方法,一般用于加载框展示
@paramrequest
/
publicvoidonBefore(Requestrequest){
}
/
在请求之后的方法,一般用于加载框隐藏
/
publicvoidonAfter(){
}
/
请求失败的时候
@paramrequest
@parame
/
publicabstractvoidonError(Requestrequest,Exceptione);
/
@paramresponse
/
publicabstractvoidonResponse(Tresponse);
}
②对Get、Post方法的简单封装
首先我们创建一个OkHttpClientManager类,由于是管理类,所以,单例加静态对象搞起
privatestaticOkHttpClientManagermInstance;
publicstaticOkHttpClientManagergetInstance(){
if(mInstance==null){
synchronized(OkHttpClientManager.class){
if(mInstance==null){
mInstance=newOkHttpClientManager();
}
}
}
returnmInstance;
}
在创建Manager对象的时候我们要把OkHttp的一些参数配置一下,顺便一提一下,由于我们我们异步get、post方法是运行在子线程中,所以这里我们添加了分发的HandlermDelivery;,重写的OkHttpClientManager构造方法如下:
privateOkHttpClientManager(){
mOkHttpClient=newOkHttpClient();
mOkHttpClient.setConnectTimeout(10,TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(10,TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(30,TimeUnit.SECONDS);
//cookieenabled
mOkHttpClient.setCookieHandler(newCookieManager(null,CookiePolicy.ACCEPT_ORIGINAL_SERVER));
mDelivery=newHandler(Looper.getMainLooper());
mGson=newGson();
}
前面的外部调用对象封装好了,这里我们开始来封装Get或Post方法,我这里以Post方法为例子,首先分析一下,post方法会有几个参数,参数一url,参数二参数params,参数三Callback(及我们上面的RequestCallBack)参数四flag(用于取消请求操作,可为空),基础代码如下:
/
通用基础的异步的post请求
@paramurl
@paramcallback
@paramtag
/
publicvoidpostAsyn(Stringurl,Param[]params,finalResultCallbackcallback,Objecttag){
Requestrequest=buildPostFormRequest(url,params,tag);
deliveryResult(callback,request);
}
那么我们再看一下deliveryResult方法到底是干什么的
/
请求回调处理方法并传递返回值
@paramcallbackMap类型请求参数
@paramrequestRequest请求
/
privatevoiddeliveryResult(ResultCallbackcallback,Requestrequest){
if(callback==null)
callback=DEFAULT_RESULT_CALLBACK;
finalResultCallbackresCallBack=callback;
//UIthread
callback.onBefore(request);
mOkHttpClient.newCall(request).enqueue(newCallback(){
@Override
publicvoidonFailure(finalRequestrequest,finalIOExceptione){
sendFailedStringCallback(request,e,resCallBack);
}
@Override
publicvoidonResponse(finalResponseresponse){
try{
finalStringresponseMessage=response.message();
finalStringresponseBody=response.body().string();
if(response.code()==200){
if(resCallBack.mType==String.class){
sendSuccessResultCallback(responseBody,resCallBack);
}else{
Objecto=mGson.fromJson(responseBody,resCallBack.mType);
sendSuccessResultCallback(o,resCallBack);
}
}else{
Exceptionexception=newException(response.code()+":"+responseMessage);
sendFailedStringCallback(response.request(),exception,resCallBack);
}
}catch(IOExceptione){
sendFailedStringCallback(response.request(),e,resCallBack);
}catch(com.google.gson.JsonParseExceptione){//Json解析的错误
sendFailedStringCallback(response.request(),e,resCallBack);
}
}
});
}
可以看到,这个方法主要是发出请求并对请求后的数据开始回调,这样我们就基本上封装好了一个post方法了,把代码这一部分的代码贴出来看看
publicclassOkHttpClientManager{
privatestaticfinalStringTAG="com.qianmo.httprequest.http.OkHttpClientManager";
privatestaticOkHttpClientManagermInstance;
//默认的请求回调类
privatefinalResultCallbackDEFAULT_RESULT_CALLBACK=newResultCallback(){
@Override
publicvoidonError(Requestrequest,Exceptione){}
@Override
publicvoidonResponse(Stringresponse){}
};
privateOkHttpClientmOkHttpClient;
privateHandlermDelivery;
privateGsonmGson;
privateGetDelegatemGetDelegate=newGetDelegate();
privatePostDelegatemPostDelegate=newPostDelegate();
privateDownloadDelegatemDownloadDelegate=newDownloadDelegate();
privateOkHttpClientManager(){
mOkHttpClient=newOkHttpClient();
mOkHttpClient.setConnectTimeout(10,TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(10,TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(30,TimeUnit.SECONDS);
//cookieenabled
mOkHttpClient.setCookieHandler(newCookieManager(null,CookiePolicy.ACCEPT_ORIGINAL_SERVER));
mDelivery=newHandler(Looper.getMainLooper());
mGson=newGson();
}
publicstaticOkHttpClientManagergetInstance(){
if(mInstance==null){
synchronized(OkHttpClientManager.class){
if(mInstance==null){
mInstance=newOkHttpClientManager();
}
}
}
returnmInstance;
}
/
外部可调用的Post异步请求方法
@paramurl请求url
@paramparams
@paramcallback请求完成后回调类
/
publicstaticvoidpostAsyn(Stringurl,Mapparams,finalResultCallbackcallback){
getInstance().getPostDelegate().postAsyn(url,params,callback,null);
}
/
异步的post请求
@paramurl
@paramparams
@paramcallback
@paramtag
/
publicvoidpostAsyn(Stringurl,Mapparams,finalResultCallbackcallback,Objecttag){
Param[]paramsArr=map2Params(params);
postAsyn(url,paramsArr,callback,tag);
}
/
通用基础的异步的post请求
@paramurl
@paramcallback
@paramtag
/
publicvoidpostAsyn(Stringurl,Param[]params,finalResultCallbackcallback,Objecttag){
Requestrequest=buildPostFormRequest(url,params,tag);
deliveryResult(callback,request);
}
/
请求回调处理方法并传递返回值
@paramcallbackMap类型请求参数
@paramrequestRequest请求
/
privatevoiddeliveryResult(ResultCallbackcallback,Requestrequest){
if(callback==null)
callback=DEFAULT_RESULT_CALLBACK;
finalResultCallbackresCallBack=callback;
//UIthread
callback.onBefore(request);
mOkHttpClient.newCall(request).enqueue(newCallback(){
@Override
publicvoidonFailure(finalRequestrequest,finalIOExceptione){
sendFailedStringCallback(request,e,resCallBack);
}
@Override
publicvoidonResponse(finalResponseresponse){
try{
finalStringresponseMessage=response.message();
finalStringresponseBody=response.body().string();
if(response.www.baiyuewang.netcode()==200){
if(resCallBack.mType==String.class){
sendSuccessResultCallback(responseBody,resCallBack);
}else{
Objecto=mGson.fromJson(responseBody,resCallBack.mType);
sendSuccessResultCallback(o,resCallBack);
}
}else{
Exceptionexception=newException(response.code()+":"+responseMessage);
sendFailedStringCallback(response.request(),exception,resCallBack);
}
}catch(IOExceptione){
sendFailedStringCallback(response.request(),e,resCallBack);
}catch(com.google.gson.JsonParseExceptione){//Json解析的错误
sendFailedStringCallback(response.request(),e,resCallBack);
}
}
});
}
/
处理请求成功的回调信息方法
@paramobject服务器响应信息
@paramcallback回调类
/
privatevoidsendSuccessResultCallback(finalObjectobject,finalResultCallbackcallback){
mDelivery.post(()->{
callback.onResponse(object);
callback.onAfter();
});
}
}
这样我们就把Post方法封装好了,同理Get方法,ok,现在我们可以来调用调用了,在调用之前我们可以对返回数据格式再来封装封装,一般我们后台返回的数据格式是类似如下:
{
"code":200,
"data":{},
"message":"登录成功"
}
而data中有可能是对象,也有可能是数组,所以我们用两个类来实现一下
CommonResultBean
packagecom.qianmo.httprequest.bean;
/
服务端返回通用接收实体
Createdbywangjitaoon15/10/30.
/
publicclassCommonResultBean{
privateStringcode;
privateTdata;
privateStringmessage;
publicStringgetCode(){
returncode;
}
publicvoidsetCode(Stringcode){
this.code=code;
}
publicTgetData(){
returndata;
}
publicvoidsetData(Tdata){
this.data=data;
}
publicStringgetMessage(){
returnmessage;
}
publicvoidsetMessage(Stringmessage){
this.message=message;
}
}
CommonResultListBean
packagecom.qianmo.httprequest.bean;
importjava.util.List;
/
服务端返回带有List数据的通用接收实体
Createdbywangjitaoon15/12/1.
/
publicclassCommonResultListBean{
privateStringcode;
privateListdata;
privateStringmessage;
publicStringgetCode(){
returncode;
}
publicvoidsetCode(Stringcode){
this.code=code;
}
publicListgetData(){
returndata;
}
publicvoidsetData(Listdata){
this.data=data;
}
publicStringgetMessage(){
returnmessage;
}
publicvoidsetMessage(Stringmessage){
this.message=message;
}
}
ok,现在还是以上面我们登录的接口为例子开始我们的方法调用,返回的数据格式如图所示
我们创建UserMenu.java类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
packagecom.qianmo.httprequest.bean;
importjava.util.List;
/
Createdbywangjitaoon2016/12/210021.
E-Mail:543441727@qq.com
用户菜单权限按钮
/
publicclassUserMenu{
/
last_login_time:2016-12-2115:40:28
member_id:1
modules:[]
phone:18900532225
real_name:超级管理员
role:{"role_id":1,"role_name":"超级管理员"}
username:superadmin
/
privateStringlast_login_time;
privateintmember_id;
privateStringphone;
privateStringreal_name;
/
role_id:1
role_name:超级管理员
/
privateRoleBeanrole;
privateStringusername;
/
module_code:100
module_id:1
module_name:首页
pid:0
type:1
value:P_index
/
privateListmodules;
publicStringgetLast_login_time(){
returnlast_login_time;
}
publicvoidsetLast_login_time(Stringlast_login_time){
this.last_login_time=last_login_time;
}
publicintgetMember_id(){
returnmember_id;
}
publicvoidsetMember_id(intmember_id){
this.member_id=member_id;
}
publicStringgetPhone(){
returnphone;
}
publicvoidsetPhone(Stringphone){
this.phone=phone;
}
publicStringgetReal_name(){
returnreal_name;
}
publicvoidsetReal_name(Stringreal_name){
this.real_name=real_name;
}
publicRoleBeangetRole(){
returnrole;
}
publicvoidsetRole(RoleBeanrole){
this.role=role;
}
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
this.username=username;
}
publicListgetModules(){
returnmodules;
}
publicvoidsetModules(Listmodules){
this.modules=modules;
}
publicstaticclassRoleBean{
privateintrole_id;
privateStringrole_name;
publicintgetRole_id(){
returnrole_id;
}
publicvoidsetRole_id(introle_id){
this.role_id=role_id;
}
publicStringgetRole_name(){
returnrole_name;
}
publicvoidsetRole_name(Stringrole_name){
this.role_name=role_name;
}
}
publicstaticclassModulesBean{
privateStringmodule_code;
privateintmodule_id;
privateStringmodule_name;
privateintpid;
privateinttype;
privateStringvalue;
publicStringgetModule_code(){
returnmodule_code;
}
publicvoidsetModule_code(Stringmodule_code){
this.module_code=module_code;
}
publicintgetModule_id(){
returnmodule_id;
}
publicvoidsetModule_id(intmodule_id){
this.module_id=module_id;
}
publicStringgetModule_name(){
returnmodule_name;
}
publicvoidsetModule_name(Stringmodule_name){
this.module_name=module_name;
}
publicintgetPid(){
returnpid;
}
publicvoidsetPid(intpid){
this.pid=pid;
}
publicintgetType(){
returntype;
}
publicvoidsetType(inttype){
this.type=type;
}
publicStringgetValue(){
returnvalue;
}
publicvoidsetValue(Stringvalue){
this.value=value;
}
}
}
所以MainActivity代码如下:
packagecom.qianmo.httprequest;
importandroid.os.Environment;
importandroid.os.Handler;
importandroid.support.v7.app.AppCompatActivity;
importandroid.os.Bundle;
importandroid.util.Log;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.ProgressBar;
importandroid.widget.TextView;
importcom.qianmo.httprequest.bean.CommonResultBean;
importcom.qianmo.httprequest.bean.UserMenu;
importcom.qianmo.httprequest.http.IRequestCallBack;
importcom.qianmo.httprequest.http.IRequestManager;
importcom.qianmo.httprequest.http.OkHttpClientManager;
importcom.qianmo.httprequest.http.RequestFactory;
importcom.qianmo.httprequest.http.ResultCallback;
importcom.squareup.okhttp.Call;
importcom.squareup.okhttp.Callback;
importcom.squareup.okhttp.FormEncodingBuilder;
importcom.squareup.okhttp.OkHttpClient;
importcom.squareup.okhttp.Request;
importcom.squareup.okhttp.RequestBody;
importcom.squareup.okhttp.Response;
importjava.io.File;
importjava.io.IOException;
importjava.util.HashMap;
importjava.util.Map;
publicclassMainActivityextendsAppCompatActivityimplementsOnClickListener{
privateHandlerhandler;
privateTextViewtv_message;
privateButtonbtn_login;
privateProgressBarprogressBar;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
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=newHandler();
btn_login.setOnClickListener(this);
}
@Override
publicvoidonClick(Viewview){
progressBar.setVisibility(View.VISIBLE);
Stringurl="http://192.168.1.123:8081/api/login";
Mapparams=newHashMap();
params.put("username","superadmin");
params.put("pwd","ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413");
OkHttpClientManager.postwww.tt951.comAsyn(url,params,
newResultCallback>(){
@Override
publicvoidonError(Requestrequest,Exceptione){
}
@Override
publicvoidonResponse(CommonResultBeanresponse){
if(response.getData()!=null){
UserMenuuserMenu=response.getData();
tv_message.setText(userMenu.getReal_name());
progressBar.setVisibility(View.GONE);
}
}
});
}
}
|
|