OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据


我们这片博文就来聊聊这个反响很不错的OkHttp了,标题是我恶搞的,本篇将着重详细的分析,探索OkHttp这个框架的使用和封装

一.追其原理

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

  • HttpURLConnection
  • HttpClient

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

注意,我们使用的IDE是Android Studio

二.使用准备

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

而关于OkHttp的官方介绍,大家可以移步这里

  • http://square.github.io/okhttp/

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

  • https://github.com/square/okhttp

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

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

因为我们会用到图片解析,所以可以加上Picasso的依赖,关于它的介绍,可以移步

  • http://square.github.io/picasso/

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

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

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

  <!--网络权限--><uses-permission android:name="android.permission.INTERNET"/>

行,大致的配置就到这里OK了,如果你还有什么不清楚的,可以去他们官网或者github上瞧一瞧,看一看,这里再送上一下下载jar的地址吧!

  • OkHttp 2.7.5 Jar下载

OkHttp内部依赖了Okio,这里也提供了jar下载地址

  • Okio 1.8.0 jar下载

三.图片加载

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

<ImageViewandroid:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/ic_launcher" /><Buttonandroid:id="@+id/btn_iv"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="图片加载" />

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

    //成功状态private static final int SUCCESS_STATUS = 1;//失败状态private static final int FAIL_STATUS = 2;//图片链接private String url = "http://d.3987.com/qiz_141118/004.jpg";

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

 //图片解析btn_iv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//初始化OkHttpOkHttpClient client = new OkHttpClient();//构建Request,解析链接,这里可选get/post方法final Request request = new Request.Builder().get().url(url).build();//添加到请求队列client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {//失败Log.i(TAG, "解析失败");}@Overridepublic void onResponse(Call call, Response response) throws IOException {//成功Message message = handler.obtainMessage();//判断,成功就传值if (response.isSuccessful()) {message.what = SUCCESS_STATUS;message.obj = response.body().bytes();handler.sendMessage(message);} else {handler.sendEmptyMessage(FAIL_STATUS);}}});}});

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

 //子线程private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case SUCCESS_STATUS://拿值byte[] result = (byte[]) msg.obj;//图片加载Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length);//设置图片iv.setImageBitmap(bitmap);break;case FAIL_STATUS://失败Log.i(TAG, "解析失败");break;}}};

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

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

四.图片裁剪

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

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

package com.lgl.okhttpgo;import android.graphics.Bitmap;import com.squareup.picasso.Transformation;/*** 裁剪图片* Created by LGL on 2016/6/19.*/
public class TailorImageView implements Transformation {@Overridepublic Bitmap transform(Bitmap source) {//得到原图片的大小,取最小值int size = Math.min(source.getWidth(), source.getHeight());//长大于宽,还是宽大于长int x = (source.getWidth() - size) / 2;int y = (source.getHeight() - size) / 2;//创建新的bitmapBitmap bitmap = Bitmap.createBitmap(source, x, y, size, size);if (bitmap != source) {//回收source.recycle();}return bitmap;}@Overridepublic String key() {return "lgl";}
}

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

case SUCCESS_STATUS://拿值byte[] result = (byte[]) msg.obj;//图片加载Bitmap bitmap = new TailorImageView().transform(BitmapFactory.decodeByteArray(result, 0, result.length));//设置图片iv.setImageBitmap(bitmap);break;

我们可以是这样的

正方形就搞定了,欧耶!

五.网络框架封装

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

  • 一般的get请求
  • 一般的post请求
  • 基于Http的文件上传
  • 文件下载
  • 加载图片
  • 支持请求回调,直接返回对象,对象集合
  • 支持session的保持

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

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

package com.lgl.okhttpgo;import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;import org.json.JSONException;
import org.json.JSONObject;import java.io.IOException;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;/*** OkHttp的封装工具类* Created by LGL on 2016/6/19.*/
public class OkHttpUtils {//TAGprivate static final String TAG = OkHttpUtils.class.getSimpleName();//声明客户端private OkHttpClient client;//防止多个线程同时访问所造成的安全隐患private volatile static OkHttpUtils okHttpUtils;//定义提交类型Jsonprivate static final MediaType JSON = MediaType.parse("application/json;charset=utf-8");//定义提交类型Stringprivate static final MediaType STRING = MediaType.parse("text/x-markdown;charset=utf-8");//子线程private Handler handler;//构造方法private OkHttpUtils() {//初始化client = new OkHttpClient();handler = new Handler(Looper.getMainLooper());}//单例模式public static OkHttpUtils getInstance() {OkHttpUtils okUtils = null;if (okHttpUtils == null) {//线程同步synchronized (OkHttpUtils.class) {if (okUtils == null) {okUtils = new OkHttpUtils();okHttpUtils = okUtils;}}}return okUtils;}/*** 请求的返回结果是json字符串** @param jsonValue* @param callBack*/private void onsuccessJsonStringMethod(final String jsonValue, final FuncJsonString callBack) {handler.post(new Runnable() {@Overridepublic void run() {if (callBack != null) {try {//解析jsoncallBack.onResponse(jsonValue);} catch (Exception e) {}}}});}/*** 求的返回结果是json对象** @param jsonValue* @param callBack*/private void onsuccessJsonObjectMethod(final String jsonValue, final FuncJsonObject callBack) {handler.post(new Runnable() {@Overridepublic void run() {if (callBack != null) {try {callBack.onResponse(new JSONObject(jsonValue));} catch (JSONException e) {e.printStackTrace();}}}});}/*** 求的返回结果是json数组** @param data* @param callBack*/private void onsuccessJsonByteMethod(final byte[] data, final FuncJsonObjectByte callBack) {handler.post(new Runnable() {@Overridepublic void run() {if (callBack != null) {callBack.onResponse(data);}}});}/*** 同步请求,不是很常用,因为会阻塞线程** @param url* @return*/public String syncGetByURL(String url) {//构建一个Request请求Request request = new Request.Builder().url(url).build();Response response = null;try {//同步请求数据response = client.newCall(request).execute();if (response.isSuccessful()) {return response.body().string();}} catch (Exception e) {}return null;}/*** 请求指定的url,返回的结果是json字符串** @param url* @param callback*/public void syncJsonStringByURL(String url, final FuncJsonString callback) {final Request request = new Request.Builder().url(url).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.i(TAG, "解析失败");}//解析成功@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null && response.isSuccessful()) {onsuccessJsonStringMethod(response.body().string(), callback);}}});}/*** 返回字符串json的接口*/interface FuncJsonString {//处理我们返回的结果void onResponse(String result);}/*** 返回json对象的接口*/interface FuncJsonObject {//处理我们返回的结果void onResponse(JSONObject jsonObject);}/*** 返回json对象的接口*/interface FuncJsonObjectByte {//处理我们返回的结果void onResponse(byte[] result);}/*** 返回json对象的接口*/interface FuncJsonObjectBitmap {//处理我们返回的结果void onResponse(Bitmap bitmap);}}

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

<TextViewandroid:id="@+id/tv_json"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="json数据" />
<Buttonandroid:id="@+id/btn_json"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="解析json数据" />

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

 //解析jsonbtn_json.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//单例初始化OkHttpUtils okHttpUtils = OkHttpUtils.getInstance();/*** 地址* 成功回调*/okHttpUtils.syncJsonStringByURL(json_url, new OkHttpUtils.FuncJsonString() {@Overridepublic void onResponse(String result) {tv_json.setText(result);Log.i(TAG,""+result);}});}});

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

//json地址
private String json_url = "https://api.douban.com/v2/book/1220562";

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

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

六.封装优化

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

     /*** 请求指定的url,返回的结果是json对象** @param url* @param callback*/public void syscJsonObjectByURL(String url, final FuncJsonObject callback) {final Request request = new Request.Builder().url(url).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.i(TAG, "解析失败");}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null && response.isSuccessful()) {onsuccessJsonObjectMethod(response.body().string(), callback);}}});}

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

    /*** 请求指定的url,返回的结果是byte字节数组** @param url* @param callback*/public void syscGetByteByURL(String url, final FuncJsonObjectByte callback) {final Request request = new Request.Builder().url(url).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.i(TAG, "解析失败");}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null && response.isSuccessful()) {onsuccessJsonByteMethod(response.body().bytes(), callback);}}});}

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

/*** 请求指定的url,返回的结果是Bitmap* @param url* @param callback*/public void syscDownloadImageByURL(String url, final FuncJsonObjectBitmap callback){final Request request = new Request.Builder().url(url).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.i(TAG, "解析失败");}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null && response.isSuccessful()) {byte [] data = response.body().bytes();Bitmap bitmap = new TailorImageView().transform(BitmapFactory.decodeByteArray(data,0,data.length));callback.onResponse(bitmap);}}});}

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

post提交表单数据

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

 /*** 向服务器提交表单** @param url      提交地址* @param params   提交数据* @param callback 提交回调*/public void sendDatafForClicent(String url, Map<String, String> params, final FuncJsonObject callback) {//表单对象,包含input开始的操作FormBody.Builder from = new FormBody.Builder();//键值对不为空,他的值也不为空if (params != null && !params.isEmpty()) {for (Map.Entry<String, String> entry : params.entrySet()) {//装载表单值from.add(entry.getKey(), entry.getValue());}}RequestBody body = from.build();//post提交Request request = new Request.Builder().url(url).post(body).build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.i(TAG, "解析失败");}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (response != null && response.isSuccessful()) {onsuccessJsonObjectMethod(response.body().string(), callback);}}});}

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

 <Buttonandroid:id="@+id/btn_post"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="POST表单提交" />

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

//post表单提交btn_post.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {OkHttpUtils okHttpUtils = OkHttpUtils.getInstance();//服务端的地址String post_url = "";//map集合HashMap<String, String> map = new HashMap<String, String>();map.put("username", "LGL");map.put("password", "12345678");okHttpUtils.sendDatafForClicent(post_url, map, new OkHttpUtils.FuncJsonObject() {@Overridepublic void onResponse(JSONObject jsonObject) {//输出结果Log.i(TAG, jsonObject.toString());}});}});

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

  • Android OkHttp完全解析 是时候来了解OkHttp了

2016/6/20补充:

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

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

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

本文的Demo我会上传到CSDN,大家可以下载

下载地址:http://download.csdn.net/detail/qq_26787115/9553992

如果大家对我有什么兴趣或者对我博客有兴趣,可以加群一起聊聊

通往Android的神奇之旅:555974449

OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据相关推荐

  1. OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据...

    OkHttp框架从入门到放弃,解析图片使用Picasso裁剪,二次封装OkHttpUtils,Post提交表单数据 我们这片博文就来聊聊这个反响很不错的OkHttp了,标题是我恶搞的,本篇将着重详细的 ...

  2. 深聊性能测试,从入门到放弃之: Windows系统性能监控(二) 资源监控器介绍及使用。

    资源监控器介绍及使用 1.引言 2.资源监视器 2.1 打开方式 2.2 基本介绍 2.3 使用 3.总结 1.引言 小屌丝:鱼哥,我看了你这篇<Windows系统性能监控(一) 性能监视器介绍 ...

  3. python自动登录并提交表单_用python模拟登录(解析cookie + 解析html + 表单提交 + 验证码识别 + excel读写 + 发送邮件)...

    老婆大人每个月都要上一个网站上去查数据,然后做报表. 为了减轻老婆大人的工作压力,所以我决定做个小程序,减轻我老婆的工作量. 准备工作 1.tesseract-ocr 这个工具用来识别验证码,非常好用 ...

  4. Scott的ASP.net MVC框架系列文章之四:处理表单数据(2)

    前几周我发表了一系列文章介绍我们正在研究的ASP.NET MVC框架.ASP.NET MVC框架为你提供了一种新的开发Web应用程序的途径,这种途径可以让应用程序变得更加层次清晰,而且更加有利于对代码 ...

  5. 小程序提交表单mysql_GitHub - kun19911227/minipro: 微信小程序提交带图片的表单

    minipro 微信小程序提交带图片的表单 目录说明 upload_images ├── pages │ ├── upload_info 提交表单 │ └── display_info 信息展示 ├─ ...

  6. 微信提交表单到服务器,微信小程序页面表单如何跟图片一起上传服务器

    拆开写. 表单提交是 wx.request 上传图片是 wx.uploadFile 你需要写一个通用图片上传接口,上传图片后台返回图片的url.这个通用接口在任何需要提交图片的表单都可以用到. 添加图 ...

  7. html把保留图片改为提交按钮,如何制作图片按钮,并为图片按钮添加提交表单和重置表单功能...

    网页中有表单,表单的默认按钮样式不是很好看,很多人为了美观使用图片做按钮. 今天中国在 一.图片按钮的制作方法 1. 定义图像形式的提交按钮. 2.用CSS把图片设为按钮的背景 3.作用,设置其bac ...

  8. json数据解析_shell从入门到放弃解析json数据(2)

    0x00 前言 json是程序猿经常遇到的数据格式,对于java,python对json的解析那是小菜一碟. 今天介绍一下shell里处理json的神器:jq 在这里先预设一个json数据,如下: j ...

  9. 入门到放弃node系列之网络模块(二)

    为什么80%的码农都做不了架构师?>>>    前言 本文首发[一名打字员] 上一节我们刚刚介绍完node的HTTP和HTTPS模块,相信我们也对nodejs有了更深层次的理解,接下 ...

最新文章

  1. cocos2dx中关于Action动作的相关API的详细介绍
  2. 基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ
  3. Android开发之ADB常用命令
  4. 【全】.net core平台单元/集成测试结果、覆盖率、圈复杂度到可视化HTML报告之路...
  5. QT Core | 信号槽03 - 自定义信号与槽
  6. jQtouch 初体验
  7. centos操作系统版本获取
  8. Hadoop2.7.3伪分布式集群搭建
  9. 手机网站和PC网站兼容的响应式网页设计
  10. Layui中的table中toolbar自定义过程
  11. Windows10如何彻底卸载MySQL
  12. Ubuntu中EasyPR环境配置
  13. Beyond Compare 激活解决办法
  14. PHPWord 表格居中和合并单元格
  15. Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
  16. nodejs串口通信
  17. iptables 流量统计
  18. sqlserver2000安装时提示挂起并重启
  19. 精彩回顾 | Dev.Together 2022 开发者生态峰会圆满落幕
  20. 2.微处理器:8088功能结构图【BIU 和 EU】 + 8088【内部各寄存器】的解释

热门文章

  1. 华为云“链”接元宇宙
  2. 【托业】【跨栏】TEST05
  3. 等保2.0(信息安全等级保护)全面解读
  4. 论文集计算机,计算机学年论文集 计算机学年论文参考文献哪里找
  5. 插曲一下:很多程序员会遇到的脱发问题
  6. 蓝桥杯算法训练-印章
  7. linux 中gzip,zip,bizp2 最常见的压缩工具
  8. 为系统添加预装软件--雨滴应用商店APP
  9. Microsoft Excel 教程:如何在 Excel 中使用数字格式?
  10. 从游戏智能到疾病诊断,腾讯「绝悟」AI 从虚拟走向现实