Okhttp的简单介绍和使用
这一周就是把之前学的Okhttp重新总结和学习了一下,之前只是在《安卓第一行代码》里面简单了解了一下这个,但是实际自己用起来还是不太熟练,可能是练的太少了吧,然后看了好多人的博客,总结一下这个。
okhttp介绍
一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献。反正就是别人大佬在前人基础上封装的一个网络库,比之前用的网络基础类HttpUrlConnection要简单很多,因为好多的事别人都帮你弄好。
网络请求发展:
HttpURLConnection—>Apache HTTP Client—>Volley—->okHttp
优势
允许连接到同一个主机地址的所有请求,提高请求效率
共享Socket,减少对服务器的请求次数
通过连接池,减少了请求延迟
缓存响应数据来减少重复的网络请求
减少了对数据流量的消耗
自动处理GZip压缩
缺点
消息回来需要切到主线程,主线程要自己去写
传入调用比较复杂。
使用步骤
第一步:添加网络权限和okhttp的包
compile ‘com.squareup.okhttp3:okhttp:3.0.1’
这个去具体官网上看下最新的是多少
第二步:创建OkhttpClient对象
OkHttpClient client=new OkHttpClient();
第三步:创建一个Request对象
Request request = new Request.Builder().url(url).build();
里面url可以添加请求的地址,可以添加请求头
第四步:调用newcall()回调方法创建一个call对象,调用它的execute()获取请求返回的数据
GET请求同步方法
OkHttpClient client=new OkHttpClient(); //创建一个okhttpClient实例
Request request = new Request.Builder().url(url) .build(); //创建一个Request实例
Response response= client.newCall(request).execute(); //调用一个newcall创建一个call对象 并execute方法发送请求并获取服务器返回的数据
String message=response.body().string();//得到返回的内容
以上就是get请求方式
1.先实例化okhttp,构建一个request,使用的是get方式,放入一个url地址就可以了,也可以通过Request.Builder设置更多的参数。
2.然后通过client发起一个请求,放入队列。等待任务完成,在Callback中取结果。
3.通过response.body().string()获取返回来的字符串。
这个body()其实就是ResponseBody的对象
GET请求异步方法
Request request = new Request.Builder().url("http://www.baidu.com").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// call 是一个接口, 是一个准备好的可以执行的request 可以取消,对位一个请求对象,只能单个请求
Log.d("233","请求失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
/**
* 通过拿到response这个响应请求,然后通过body().string(),拿到请求到的数据
*这里最好用string() 而不要用toString()
* toString()每个类都有的,是把对象转换为字符串
* string()是把流转为字符串
*/
result = response.body().string();
同步提交和异步提交的差别
**同步请求只能同一个时刻发起一个任务
异步请求可以同一个时刻发起多个请求**
同步和异步的概念对于很多人来说是一个模糊的概念,是一种似乎只能意会不能言传的东西。其实我们的生活中存在着很多同步异步的例子。比如:你叫我去吃饭,我听到了就立刻和你去吃饭,如果我们有听到,你就会一直叫我,直到我听见和你一起去吃饭,这个过程叫同步;异步过程指你叫我去吃饭,然后你就去吃饭了,而不管我是否和你一起去吃饭。而我得到消息后可能立即就走,也可能过段时间再走。如果我请你吃饭,就是同步,如果你请我吃饭就用异步,这样你比较省钱。哈哈哈。。。
在计算机领域,同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
Post请求
From表单形式
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("username","xiaoyi")
.build();
Request request = new Request.Builder()
.post(body)
.url(url)
. build();
client.newCall(request).enqueue(new Callback() {...});
json参数形式
kHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json); Request request = new Request.Builder() .post(body) .url(url). build(); client.newCall(request).enqueue(new Callback() {...});
文件上传
OkHttpClient client = new OkHttpClient();
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), fiDatale);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "head_img", fileBody)
.addFormDataPart("name", "xiaoyi").build();
Request request = new Request.Builder() .url(url) .post(requestBody) .build();
client.newCall(request).enqueue(new Callback() {...});
文件下载
url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";
//构建request对象
Request request = new Request.Builder().url(url).build();
OkHttpClient client = new OkHttpClient();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream inputStream = response.body().byteStream();
FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/logo.jpg"));
byte[] buffer = new byte[2048];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
}
fileOutputStream.flush();
Log.d("wuyinlei", "文件下载成功...");
}
});
超时设置
okhttp3.0之前:
client.setConnectTimeout(10, TimeUnit.SECONDS);
client.setWriteTimeout(10, TimeUnit.SECONDS);
client.setReadTimeout(30, TimeUnit.SECONDS);
okhttp3.0之后:
client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
client.newBuilder().readTimeout(10,TimeUnit.SECONDS);
client.newBuilder().writeTimeout(10,TimeUnit.SECONDS);
okhttp的Doem
就是简单的请求一下百度的网址,然后模拟表单请求
布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<Button
android:id="@+id/btn_1"
android:layout_width="80dp"
android:layout_height="match_parent"
android:text="同步请求"/>
<Button
android:id="@+id/btn_2"
android:layout_width="80dp"
android:layout_height="match_parent"
android:text="异步请求"/>
<Button
android:id="@+id/btn_3"
android:layout_width="80dp"
android:layout_height="match_parent"
android:text="表单提交"/>
<Button
android:id="@+id/btn_4"
android:layout_width="80dp"
android:layout_height="match_parent"
android:text="文件下载"/>
</LinearLayout>
<TextView
android:id="@+id/iv_show"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
主activity
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button syncGet;
private Button asyncget;
private Button post;
private Button fileDowmload;
private TextView textView;
private String result;
private static OkHttpClient client = new OkHttpClient();
/**
* 设置连接超时的设定,在静态方法内,构造方法被调用时候就已经被激活
* @param savedInstanceState
*/
static {
client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
client.newBuilder().readTimeout(10,TimeUnit.SECONDS);
client.newBuilder().writeTimeout(10,TimeUnit.SECONDS);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initialize();
initListener();
}
/**
* 事件监听
*/
private void initListener(){
syncGet.setOnClickListener(this);
asyncget.setOnClickListener(this);
post.setOnClickListener(this);
fileDowmload.setOnClickListener(this);
}
/**
* 初始化布局
*/
private void initialize(){
syncGet = (Button)findViewById(R.id.btn_1);
asyncget = (Button)findViewById(R.id.btn_2);
post = (Button)findViewById(R.id.btn_3);
fileDowmload = (Button)findViewById(R.id.btn_4);
textView = (TextView)findViewById(R.id.iv_show);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_1:
initSyncData();
break;
case R.id.btn_2:
//直接调用
initAsyncGet();
break;
case R.id.btn_3:
initPost();
break;
case R.id.btn_4:
downLoadFile();
break;
}
}
/**
* geti请求同步
*/
private void initSyncData(){
new Thread(new Runnable() {
@Override
public void run() {
try {
Request request = new Request.Builder().url("http://www.baidu.com").build();
Response response = client.newCall(request).execute();
result = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(result);
Log.d("233","sync");
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 异步请求
*/
private void initAsyncGet(){
new Thread(new Runnable() {
@Override
public void run() {
Request request = new Request.Builder().url("http://www.baidu.com").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// call 是一个接口, 是一个准备好的可以执行的request 可以取消,对位一个请求对象,只能单个请求
Log.d("233","请求失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
/**
* 通过拿到response这个响应请求,然后通过body().string(),拿到请求到的数据
*这里最好用string() 而不要用toString()
* toString()每个类都有的,是把对象转换为字符串
* string()是把流转为字符串
*/
result = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(result);
}
});
}
});
}
}).start();
}
/**
* 表单提交
*/
private void initPost(){
String url = "http://112.124.22.238:8081/course_api/banner/query";
FormBody formBody = new FormBody.Builder()
.add("type","1")
.build();
final Request request = new Request.Builder().url(url)
.post(formBody).build();
new Thread(new Runnable() {
@Override
public void run() {
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText("成功");
}
});
}
});
}
}).start();
}
/**
* 文件下载
*/
private void downLoadFile(){
String url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";
Request request = new Request.Builder().url(url).build();
OkHttpClient client = new OkHttpClient();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//请求的结果转换成字节流
InputStream inputStream = response.body().byteStream();
/**
* 在这里要加上权限 在mainfests文件中
* <uses-permission android:name="android.permission.INTERNET"/>
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
*/
//输出流
FileOutputStream fileOutputStream = new FileOutputStream(new File("logo.jpg"));
//定义一个字节数组
byte[] buffer = new byte[2048];
int len = 0;
while((len =inputStream.read(buffer))!=-1){
//写出文件
fileOutputStream.write(buffer,0,len);
}
//关闭输出流
fileOutputStream.flush();
Log.d("233","下载成功");
}
});
}
}
对okhttp的封装
如果每次一次请求都要按照上面的写一大堆的话,就是觉得很麻烦,然后可以把他们封装一下,这样下次调用时候就能方便点。
类似这种
封装的okhttpManager
package com.example.hasee.okhttpdome;
import android.os.Handler;
import android.os.Looper;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* 封装okhttp
*/
public class OkHttpManager {
/**
* 静态实例
*/
private static OkHttpManager sokHttpManager;
/**
* okhttpclient实例
*/
private OkHttpClient mClient;
/**
* 请求数据必须在子线程里面,所以用handler
*/
private Handler mHandler;
/**
* 构造方法
*/
private OkHttpManager() {
mClient = new OkHttpClient();
/**
* 直接设置超时这些
*/
mClient.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
mClient.newBuilder().readTimeout(10, TimeUnit.SECONDS);
mClient.newBuilder().writeTimeout(10, TimeUnit.SECONDS);
/**
* 初始化handler
*/
mHandler = new Handler(Looper.getMainLooper());
}
/**
* 单例模式
*/
public static OkHttpManager getInstance(){
if (sokHttpManager == null){
sokHttpManager = new OkHttpManager();
}
return sokHttpManager;
}
//-----------------同步请求-----------------------------------------
/**
* 对外提供get方法,
*/
public static Response getSync(String url){
//通过实例获取调用内部的方法
return sokHttpManager.inner_getSync(url);
}
/**
* get的内部的方法
*/
private Response inner_getSync(String url){
Request request = new Request.Builder().url(url).build();
Response response = null;
try {
response = mClient.newCall(request).execute();
}catch (IOException e){
e.printStackTrace();
}
return response;
}
/**
* 对外获取同步的string方法
*/
public static String getSyncString(String url){
return sokHttpManager.inner_getSynString(url);
}
/**
* 同步的方法
*/
private String inner_getSynString(String url){
String result = null;
try {
//结果转换为字符串
result = inner_getSync(url).body().string();
}catch (IOException e){
e.printStackTrace();
}
return result;
}
//------------------异步请求数据-------------------------------------------------
/**
* 数据回调接口
*/
public interface DataCallBack{
void requestFailure(Request request,IOException e);
void requestSuccess(String result) throws Exception;
}
/**
* 分发失败的时候调用
*
* @param request
* @param e
* @param callBack
*/
private void deliverDataFailure(final Request request, final IOException e, final DataCallBack callBack) {
/**
* 在这里使用异步处理
*/
mHandler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
callBack.requestFailure(request, e);
}
}
});
}
/**
* 分发成功的时候调用
*
* @param result
* @param callBack
*/
private void deliverDataSuccess(final String result, final DataCallBack callBack) {
/**
* 在这里使用异步线程处理
*/
mHandler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
try {
callBack.requestSuccess(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
//-------------------------异步的方式请求数据--------------------------
public static void getAsync(String url, DataCallBack callBack) {
getInstance().inner_getAsync(url, callBack);
}
/**
* 内部逻辑请求的方法
*
* @param url
* @param callBack
* @return
*/
private void inner_getAsync(String url, final DataCallBack callBack) {
final Request request = new Request.Builder().url(url).build();
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
deliverDataFailure(request, e, callBack);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = null;
try {
result = response.body().string();
} catch (IOException e) {
deliverDataFailure(request, e, callBack);
}
deliverDataSuccess(result, callBack);
}
});
}
/**
* 对外的接口
* @param url
* @param callBack
*/
public static void getAsync(String url,Map<String, String> params,DataCallBack callBack){
getInstance().inner_postAsync(url,params,callBack);
}
private void inner_postAsync(String url, Map<String,String> params, final DataCallBack callBack){
RequestBody requestBody = null;
if (params==null){
params = new HashMap<>();
}
FormBody.Builder builder = new FormBody.Builder();
//对参加的参数进行遍历
for(Map.Entry<String,String>map:params.entrySet()){
String key = map.getKey().toString();
String value = null;
//判断值是否为空
if (map.getValue()==null){
value = "";
}else {
value = map.getValue();
}
//添加到formbody
builder.add(key,value);
}
requestBody = builder.build();
//返回结果
final Request request = new Request.Builder().url(url).post(requestBody).build();
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
deliverDataFailure(request,e,callBack);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
deliverDataSuccess(result,callBack);
}
});
}
//-----------------------文件下载---------------------------------------------------
public static void downloadAsync(String url,String desDir,DataCallBack callBack){
getInstance().inner_downloadAsync(url,desDir,callBack);
}
/**
*
* @param url 下载地址
* @param desDir 目标地址
* @param callBack
*/
private void inner_downloadAsync(final String url,final String desDir,final DataCallBack callBack){
final Request request = new Request.Builder().url(url).build();
mClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
deliverDataFailure(request,e,callBack);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream inputStream = null;
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
File file = new File(desDir,getFileName(url));
inputStream = response.body().byteStream();
fileInputStream = new FileInputStream(file);
int len = 0;
byte[] bytes = new byte[2048];
//循环读取数据
while ((len = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, len);
}
//关闭文件输出流
fileOutputStream.flush();
//调用分发数据成功的方法
deliverDataSuccess(file.getAbsolutePath(), callBack);
}catch (IOException e){
//失败后
deliverDataFailure(request,e,callBack);
e.printStackTrace();
}finally {
if (inputStream!=null){
inputStream.close();
}
if (fileOutputStream!=null){
fileOutputStream.close();
}
}
}
});
}
/**
* 根据文件url获取文件的路径名字
*
* @param url
* @return
*/
private String getFileName(String url) {
int separatorIndex = url.lastIndexOf("/");
String path = (separatorIndex < 0) ? url : url.substring(separatorIndex + 1, url.length());
return path;
}
}
总结
就把简单的例子总结了一下,但是具体的源代码还没看,对网络请求这块运用有了基本的理解。
https://github.com/sakurakid/okhttpDome是Dome的地址,封装的http代码也在里面
希望对别人有帮助