配色: 字号:
OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据
2016-10-11 | 阅:  转:  |  分享 
  
OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据

一.追其原理



Android系统提供了两种HTTP通信类

HttpURLConnection

HttpClient

Google推荐使用HttpURLConnection,这个没必要多说,事实上,我这篇写的应该算是比较晚了,很多优秀的博文都已经提出了这些观点了,那我也就不好意思重复的说废话了,不过我还是得吐槽一下,HttpURLConnection是在是太难用了,而且功能也实在是太少了,虽然Github上封装的框架还真是不少,不过依然不是特别好用,而Google自己也在寻求解决的办法,如果你看过android4.4的源码,你就应该知道,Google把HttpURLConnection替换成了OkHttp,而OkHttp走到现在,已经是相对来说,比较成熟的框架了,那我们为何不去使用它呢?而且现在学习OkHttp的资料和文章实在是太多了,根本不需要什么学习成本的,搜索一下,马上就有一大堆,既然如此,我们今儿个就来看看这个花姑凉长什么样吧!各位小司机,跟着老司机一起上车吧!



注意,我们使用的IDE是AndroidStudio

二.使用准备



肯定要配置一下啦,我们首先新建一个工程——OkHttpGo,这名字好听,我就不加demo或者test了,这样显得有点low,项目我们基于5.0Lollipop来开发





如果想看源码,可以去Github上

我们既然要使用,就根据github上来吧,加入依赖,把依赖添加到build.gradle中,当然,他是提供jar的,你如果用Eclipse获取喜欢用jar,你也可以直接下载jar

compile''com.squareup.okhttp3:okhttp:3.3.1''



这个库,我下篇博文会介绍到,这里你只要知道是这么添加依赖和使用就可以了

compile''com.squareup.picasso:picasso:2.5.2''



记住,网络的使用,是需要添加权限的哦!







行,大致的配置就到这里OK了,

三.图片加载



我们先从图片加载说起,最起码先定义一下布局呀


android:id="@+id/iv"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@mipmap/ic_launcher"/>




android:id="@+id/btn_iv"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="图片加载"/>



非常简陋的一个布局,就一个button和一个imageview,现在我们就是点击按钮,然后解析显示在控件上,这对于OkHttp来说,应该是怎么使用的呢?注意,现在演示的,都还只是没有封装的前提下,我们首先做一些准备工作

//成功状态

privatestaticfinalintSUCCESS_STATUS=1;

//失败状态

privatestaticfinalintFAIL_STATUS=2;



//图片链接

privateStringurl="http://d.3987.com/qiz_141118/004.jpg";



这里我定义了两个常量,分别是解析成功失败的状态,又定义了一张图片的链接,图片是网上的以上美女图片,好的,这些都准备好了,现在我们就可以来书写OkHttp相关的类了

//图片解析

btn_iv.setOnClickListener(newView.OnClickListener(){

@Override

publicvoidonClick(Viewv){

//初始化OkHttp

OkHttpClientclient=newOkHttpClient();

//构建Request,解析链接,这里可选get/post方法

finalRequestrequest=newRequest.Builder().get().url(url).build();

//添加到请求队列

client.newCall(request).enqueue(newCallback(){

@Override

publicvoidonFailure(Callcall,IOExceptione){

//失败

Log.i(TAG,"解析失败");

}



@Override

publicvoidonResponse(Callcall,Responseresponse)throwsIOException{

//成功

Messagemessage=handler.obtainMessage();

//判断,成功就传值

if(response.isSuccessful()){

message.what=SUCCESS_STATUS;

message.obj=response.body().bytes();

handler.sendMessage(message);

}else{

handler.sendEmptyMessage(FAIL_STATUS);

}

}

});

}

});



可以看到,它使用和Volley有点类似,个人感觉,其实也就是那么几个步骤,首先初始化,然后设置一下乱七八糟的属性,最后添加到队列中,返回两个回调,成功和失败,是吧,我们这个时候就直接用handler去发消息了

//子线程

privateHandlerhandler=newHandler(){

@Override

publicvoidhandleMessage(Messagemsg){

super.handleMessage(msg);

switch(msg.what){

caseSUCCESS_STATUS:

//拿值

byte[]result=(byte[])msg.obj;

//图片加载

Bitmapbitmap=BitmapFactory.decodeByteArray(result,0,result.length);

//设置图片

iv.setImageBitmap(bitmap);

break;

caseFAIL_STATUS:

//失败

Log.i(TAG,"解析失败");

break;

}

}

};



得出来的效果,用一张图来表示就绰绰有余了



OK,图片解析的就已经实现了

四.图片裁剪



现在呢,我们可以看到是一个美女的图片,但是如果我们图片比较大,而我们不需要这么大,比如长这样?



如果我们不想要这么大的图片,又或者说,我们想要一张正方形一样整齐的图片,我们该怎么去做?还记得我们添加的picasso图片框架吗?他就可以做到,我们可以用它的功能写一个工具类来帮助我们裁剪,这个工具类写起来也没有多麻烦

packagecom.lgl.okhttpgo;



importandroid.graphics.Bitmap;



importcom.squareup.picasso.Transformation;



/

裁剪图片

CreatedbyLGLon2016/6/19.

/

publicclassTailorImageViewimplementsTransformation{



@Override

publicBitmaptransform(Bitmapsource){



//得到原图片的大小,取最小值

intsize=Math.min(source.getWidth(),source.getHeight());

//长大于宽,还是宽大于长

intx=(source.getWidth()-size)/2;

inty=(source.getHeight()-size)/2;

//创建新的bitmap

Bitmapbitmap=Bitmap.createBitmap(source,x,y,size,size);



if(bitmap!=source){

//回收

source.recycle();

}

returnbitmap;

}



@Override

publicStringkey(){



return"lgl";

}

}



我们使用的话,就在我们解析成功的时候调用就可以了,

caseSUCCESS_STATUS:

//拿值

byte[]result=(byte[])msg.obj;

//图片加载

Bitmapbitmap=newTailorImageView().transform(BitmapFactory.decodeByteArray(result,0,result.length));

//设置图片

iv.setImageBitmap(bitmap);

break;

我们可以是这样的



正方形就搞定了,欧耶!

五.网络框架封装



事实上,我们上面所说的,都还是有些许繁杂了,毕竟我们不应该重复的去写这么多麻烦的代码,对吧,现在我们来对他进行一个封装,而对于OkHttp,他有以下的几个功能

一般的get请求

一般的post请求

基于Http的文件上传

文件下载

加载图片

支持请求回调,直接返回对象,对象集合

支持session的保持

我们要封装一个OkHttp的话,也就是围绕着他的这几个功能来二次开发了,好的,小司机们,我们继续开车吧!污污污污污…..



我们写一个OkHttpUtils,其实还算是比较简单的,因为我们实际上没写多少内容

packagecom.lgl.okhttpgo;



importandroid.graphics.Bitmap;

importandroid.os.Handler;

importandroid.os.Looper;

importandroid.util.Log;



importorg.json.JSONException;

importorg.json.JSONObject;



importjava.io.IOException;



importokhttp3.Call;

importokhttp3.Callback;

importokhttp3.MediaType;

importokhttp3.OkHttpClient;

importokhttp3.Request;

importokhttp3.Response;



/

OkHttp的封装工具类

CreatedbyLGLon2016/6/19.

/

publicclassOkHttpUtils{



//TAG

privatestaticfinalStringTAG=OkHttpUtils.class.getSimpleName();



//声明客户端

privateOkHttpClientclient;

//防止多个线程同时访问所造成的安全隐患

privatevolatilestaticOkHttpUtilsokHttpUtils;

//定义提交类型Json

privatestaticfinalMediaTypeJSON=MediaType.parse("application/json;charset=utf-8");

//定义提交类型String

privatestaticfinalMediaTypeSTRING=MediaType.parse("text/x-markdown;charset=utf-8");

//子线程

privateHandlerhandler;



//构造方法

privateOkHttpUtils(){

//初始化

client=newOkHttpClient();

handler=newHandler(Looper.getMainLooper());

}





//单例模式

publicstaticOkHttpUtilsgetInstance(){

OkHttpUtilsokUtils=null;

if(okHttpUtils==null){

//线程同步

synchronized(OkHttpUtils.class){

if(okUtils==null){

okUtils=newOkHttpUtils();

okHttpUtils=okUtils;

}

}

}

returnokUtils;

}



/

请求的返回结果是json字符串



@paramjsonValue

@paramcallBack

/

privatevoidonsuccessJsonStringMethod(finalStringjsonValue,finalFuncJsonStringcallBack){

handler.post(newRunnable(){

@Override

publicvoidrun(){

if(callBack!=null){

try{

//解析json

callBack.onResponse(jsonValue);

}catch(Exceptione){



}

}

}

});

}



/

求的返回结果是json对象



@paramjsonValue

@paramcallBack

/

privatevoidonsuccessJsonObjectMethod(finalStringjsonValue,finalFuncJsonObjectcallBack){

handler.post(newRunnable(){

@Override

publicvoidrun(){

if(callBack!=null){

try{

callBack.onResponse(newJSONObject(jsonValue));

}catch(JSONExceptione){

e.printStackTrace();

}

}

}

});

}





/

求的返回结果是json数组



@paramdata

@paramcallBack

/

privatevoidonsuccessJsonByteMethod(finalbyte[]data,finalFuncJsonObjectBytecallBack){

handler.post(newRunnable(){

@Override

publicvoidrun(){

if(callBack!=null){

callBack.onResponse(data);

}

}

});

}



/

同步请求,不是很常用,因为会阻塞线程



@paramurl

@return

/

publicStringsyncGetByURL(Stringurl){

//构建一个Request请求

Requestrequest=newRequest.Builder().url(url).build();

Responseresponse=null;



try{

//同步请求数据

response=client.newCall(request).execute();



if(response.isSuccessful()){

returnresponse.body().string();

}

}catch(Exceptione){



}



returnnull;

}





/

请求指定的url,返回的结果是json字符串



@paramurl

@paramcallback

/

publicvoidsyncJsonStringByURL(Stringurl,finalFuncJsonStringcallback){

finalRequestrequest=newRequest.Builder().url(url).build();

client.newCall(request).enqueue(newCallback(){

@Override

publicvoidonFailure(Callcall,IOExceptione){

Log.i(TAG,"解析失败");

}



//解析成功

@Override

publicvoidonResponse(Callcall,Responseresponse)throwsIOException{

if(response!=null&&response.isSuwww.hunanwang.netccessful()){

onsuccessJsonStringMethod(response.body().string(),callback);

}

}

});

}





/

返回字符串json的接口

/

interfaceFuncJsonString{

//处理我们返回的结果

voidonResponse(Stringresult);

}



/

返回json对象的接口

/

interfaceFuncJsonObject{

//处理我们返回的结果

voidonResponse(JSONObjectjsonObject);

}



/

返回json对象的接口

/

interfaceFuncJsonObjectByte{

//处理我们返回的结果

voidonResponse(byte[]result);

}



/

返回json对象的接口

/

interfaceFuncJsonObjectBitmap{

//处理我们返回的结果

voidonResponse(Bitmapbitmap);

}



}

这里可以看到,我们基本上没做什么东西,对吧,只是把常用的方法都复写作了一些简单的操作而已,而且我们的注释也写的十分详细,你需要扩展的话,直接扩展就好了,这样,我们去验证一下,xml中加上


android:id="@+id/tv_json"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="json数据"/>


android:id="@+id/btn_json"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="解析json数据"/>

好的,什么初始化的我就不写出来了,直接看点击事件

//解析json

btn_json.setOnClickListener(newView.OnClickListener(){

@Override

publicvoidonClick(Viewv){

//单例初始化

OkHttpUtilsokHttpUtils=OkHttpUtils.getInstance();

/

地址

成功回调

/

okHttpUtils.syncJsonStringByURL(json_url,newOkHttpUtils.FuncJsonString(){

@Override

publicvoidonResponse(Stringresult){

tv_json.setText(result);

Log.i(TAG,""+result);

}

});

}

});



可以看到,是不是非常的简单就OK了。我们只要定义传url进入就可以了,而接口,我们使用的是豆瓣的接口

//json地址

privateStringjson_url="https://api.douban.com/v2/book/1220562";

这样我们可以看下运行结果



当然,我也是只提供一种思路罢了,这个封装类并不完善,还需要你自己根据需求来实施,好的,我这里也就继续来优化一下了

六.封装优化



前面可以看到,我们已经封装好了一个工具类,但是并不完善,现在呢,我们就完善的封装一下,当然,也只是针对功能点去优化,比如刚才我们只封装了一个解析返回json字符串,现在我们来一个解析直接返回一个json对象,嘿嘿,怎么做呢?

/

请求指定的url,返回的结果是json对象



@paramurl

@paramcallback

/

publicvoidsyscJsonObjectByURL(Stringurl,finalFuncJsonObjectcallback){

finalRequestrequest=newRequest.Builder().url(url).build();

client.newCall(request).enqueue(newCallback(){

@Override

publicvoidonFailure(Callcall,IOExceptione){

Log.i(TAG,"解析失败");

}



@Override

publicvoidonResponse(Callcall,Responseresponse)throwsIOException{

if(response!=null&&respowww.shanxiwang.netnse.isSuccessful()){

onsuccessJsonObjectMethod(response.body().string(),callback);

}

}

});

}



跟之前的其实很类似,同样的,我们可以返回byte字节数组

/

请求指定的url,返回的结果是byte字节数组



@paramurl

@paramcallback

/

publicvoidsyscGetByteByURL(Stringurl,finalFuncJsonObjectBytecallback){

finalRequestrequest=newRequest.Builder().url(url).build();

client.newCall(request).enqueue(newCallback(){

@Override

publicvoidonFailure(Callcall,IOExceptione){

Log.i(TAG,"解析失败");

}



@Override

publicvoidonResponse(Callcall,Responseresponse)throwsIOException{

if(response!=null&&response.isSuccessful()){

onsuccessJsonByteMethod(response.body().bytes(),callback);

}

}

});

}



我们也看到了,我们还剩下Bitmap,我们还自带裁剪功能哦,哈哈



/

请求指定的url,返回的结果是Bitmap

@paramurl

@paramcallback

/

publicvoidsyscDownloadImageByURL(Stringurl,finalFuncJsonObjectBitmapcallback){

finalRequestrequest=newRequest.Builder().url(url).build();

client.newCall(request).enqueue(newCallback(){

@Override

publicvoidonFailure(Callcall,IOExceptione){

Log.i(TAG,"解析失败");

}



@Override

publicvoidonResponse(Callcall,Responseresponse)throwsIOException{

if(response!=null&&response.isSuccessful()){

byte[]data=response.body().bytes();

Bitmapbitmap=newTailorImageView().transform(BitmapFactory.decodeByteArray(data,0,data.length));

callback.onResponse(bitmap);

}

}

});

}



到这里,基本的get封装就应该差不多写完了,但是别忘了,论post的重要性,既然如此,那我们就继续封装,首先实现的一个功能

post提交表单数据



开发中,也是有诸多需要post的地方的,毕竟安全性,传输都是个很不错的选择,我们继续写方法

/

向服务器提交表单



@paramurl提交地址

@paramparams提交数据

@paramcallback提交回调

/

publicvoidsendDatafForClicent(Stringurl,Mapparams,finalFuncJsonObjectcallback){

//表单对象,包含input开始的操作

FormBody.Builderfrom=newFormBody.Builder();

//键值对不为空,他的值也不为空

if(params!=null&&!params.isEmpty()){

for(Map.Entryentry:params.entrySet()){

//装载表单值

from.add(entry.getKey(),entry.getValue());

}

}

RequestBodybody=from.build();

//post提交

Requestrequest=newRequest.Builder().url(url).post(body).build();

client.newCall(request).enqueue(newCallback(){

@Override

publicvoidonFailure(Callcall,IOExceptione){

Log.i(TAG,"解析失败");

}



@Override

publicvoidonResponse(Callcall,Responseresponse)throwsIOException{

if(response!=null&&response.isSuccessful()){

onsuccessJsonObjectMethod(response.body().string(),callback);

}

}

});

}





这里没有服务端,所以就不能测试了,我这里也就教大家怎么使用就好了,首先xml中定义一个按钮


android:id="@+id/btn_post"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="POST表单提交"/>



我们可以直接看他的点击事件

//post表单提交

btn_post.setOnClickListener(newView.OnClickListener(){

@Override

publicvoidonClick(Viewv){

OkHttpUtilsokHttpUtils=OkHttpUtils.getInstance();



//服务端的地址

Stringpost_url="";

//map集合

HashMapmap=newHashMap();

map.put("username","LGL");

map.put("password","12345678");



okHttpUtils.sendDatafForClicent(post_url,map,newOkHttpUtils.FuncJsonObject(){

@Override

publicvoidonResponse(JSONObjectjsonObject){

//输出结果

Log.i(TAG,jsonObject.toString());

}

});

}

});



OK,这样就提交了表单,这就是一个完整的封装过程了,如果你问,那我们普通的请求怎么办呢?额,你看了这么久还不熟悉他的套路?我嘴角微微一笑,你的司机之路还很长啊,咳咳,跑题了,如果大家还有什么疑问的话,可以去鸿洋那里看看,我相信现在很多的文章都将了很多的基本使用的,所以我也不是想怎么去讲解析json什么的

AndroidOkHttp完全解析是时候来了解OkHttp了

2016/6/20补充:



Post提交数据,应该是这样判断的

if(params!=null&&!params.isEmpty())



有个!的判断,在Demo里面是没有的,现在及时改正了

献花(0)
+1
(本文系网络学习天...首藏)