目前Android中的网络请求最主要的就是UrlConnection和OkHttp了。而UrlConnection听说在安卓4.4以后也在内部实现了OkHttp。网络上OkHttp的封装框架也挺多比如鸿羊大神的okhttputils。框架虽有很多,基础我们更是需要了解的 ,看他们都是封装的啥内容。首先先从其最基本的用法开始
OkHttp的用法步骤:
引入最新的gradle依赖
compile 'com.squareup.okhttp3:okhttp:3.5.0'
compile 'com.squareup.okio:okio:1.11.0'
Get:
- 创建okHttpClient的对象。我们可直接new出来 也可以通过OkHttpClient.Builder()构建。
- 创建Request对象。
- 封装成一个请求的任务Call
- 执行任务 call.execute();是同步请求直接返回Response但需要在子线程中执行。call.enqueue()时异步请求。内部一个执行的回调。
Post:
- 创建okHttpClient的对象。我们可直接new出来 也可以通过OkHttpClient.Builder()构建。
- 创建RequestBody
- 创建Request对象。
- 封装成一个请求的任务Call
- 执行任务 call.execute();是同步请求直接返回Response但需要在子线程中执行。call.enqueue()时异步请求。内部一个执行的回调。
示例代码:(官方文档)
package com.chs.okhttpdemo;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;
public class MainActivity extends AppCompatActivity {
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private static final MediaType MEDIA_TYPE_JPG = MediaType.parse("application/octet-stream");
OkHttpClient okHttpClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1.拿到OkHttpClient对象
okHttpClient = new OkHttpClient.Builder().
connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
public void doGet(View view) {
//创建request对象
Request.Builder builder = new Request.Builder();
Request request = builder.get().url("http://192.168.1.63:8080/album/login?name=chs&password=123").build();
execute(request);
}
//post提交(表单)键值对
public void doPost(View view) {
//拿到body的构建器
FormBody.Builder builder = new FormBody.Builder();
//添加参数
builder.add("name", "chs")
.add("password", "123");
//拿到requestBody
RequestBody requestBody = builder.build();
//创建request对象
Request request = new Request.Builder()
.url("http://192.168.1.63:8080/album/login")
.post(requestBody)
.build();
execute(request);
}
//post提交String 这个API最好不要发送大于1M的字符串
public void doPostString(View view) {
String postBody = "{name:chs,pwd:123}";
//创建requestBody
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody);
//创建request
Request request = new Request.Builder()
.url("http://192.168.1.63:8080/album/login")
.post(requestBody)
.build();
execute(request);
}
//post提交流
public void doPostStream(View view) {
RequestBody requestBody = new RequestBody() {
@Override
public MediaType contentType() {
return MEDIA_TYPE_MARKDOWN;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("doPostStream\n");
sink.writeUtf8("{name:doPostStream,title:doPostStream}");
}
};
Request request = new Request.Builder()
.url("http://192.168.1.63:8080/album/login")
.post(requestBody)
.build();
execute(request);
}
//post提交File
public void doPostFile(View view) {
//图片在手机上的路径
String path = Environment.getExternalStorageDirectory().getPath()+"/BXT_SetPic/20170118/1484724630838.jpg";
LogUtil.i("path:"+path);
File file = new File(path);
//创建requestBody
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, file);
Request request = new Request.Builder()
.url("http://192.168.1.63:8080/album/login")
.post(requestBody)
.build();
execute(request);
}
//post提交Multipart 键值对和file一起提交
public void doPostMultipart(View view) {
//图片在手机上的路径
String path = Environment.getExternalStorageDirectory().getPath()+"/BXT_SetPic/20170118/1484724630838.jpg";
LogUtil.i("pth:"+path);
File file = new File(path);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("name", "Square")
.addFormDataPart("password", "1111")
.addFormDataPart("image", "1484724630838.jpg", RequestBody.create(MEDIA_TYPE_JPG, file))
.build();
//封装一层来获取上传的进度
CountingRequestBody countRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.OnProgressListener() {
@Override
public void OnProgress(long byteWrite, long contentLength) {
LogUtil.i(byteWrite+"/"+contentLength);
}
});
Request request = new Request.Builder()
.url("http://192.168.1.63:8080/album/login")
.post(countRequestBody)
.build();
execute(request);
}
//下载
public void doDownLoad(View view) {
//创建request对象
Request.Builder builder = new Request.Builder();
Request request = builder.get().url("http://192.168.1.63:8080/album//files/album.jpg").build();
//封装成一个请求的任务
Call call = okHttpClient.newCall(request);
//同步的请求 Response response = call.execute();
// 执行请求(异步的请求)
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
LogUtil.i("请求失败:" + e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
LogUtil.i("请求成功:");
//总的长度
long totalLength = response.body().contentLength();
//下载的进度
long sum = 0;
InputStream is = response.body().byteStream();
int len = 0;
byte [] buff = new byte[1024];
File file = new File(Environment.getExternalStorageDirectory(),"album.jpg");
FileOutputStream os = new FileOutputStream(file);
while ((len=is.read(buff))!=-1){
os.write(buff,0,len);
sum+=len;
LogUtil.i(sum+"/"+totalLength);
}
os.flush();;
os.close();
is.close();
LogUtil.i("success");
}
});
}
private void execute(Request request) {
//封装成一个请求的任务
Call call = okHttpClient.newCall(request);
//同步的请求 Response response = call.execute();
// 执行请求(异步的请求)
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
LogUtil.i("请求失败:" + e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
LogUtil.i("请求成功:" + response.body().string());
}
});
}
}
因为RequestBody没有提供上传的进度,所以在上传的时候包装RequestBody用来计算上传的进度
package com.chs.okhttpdemo;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;
/**
* 作者:chs on 2017/1/19 16:05
* 邮箱:657083984@qq.com
* 包装RequestBody用来计算上传的进度
*/
public class ProgressRequestBody extends RequestBody {
//真正的mRequestBody
private RequestBody mRequestBody;
//上传回调接口
private OnProgressListener mProgressListener;
public ProgressRequestBody(RequestBody requestBody, OnProgressListener progressListener) {
mRequestBody = requestBody;
mProgressListener = progressListener;
}
public interface OnProgressListener {
void OnProgress(long byteWrite,long contentLength);
}
@Override
public MediaType contentType() {
return mRequestBody.contentType();
}
@Override
public long contentLength() {
try {
return mRequestBody.contentLength();
} catch (IOException e) {
return -1;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
CountingSink countingSink = new CountingSink(sink);
BufferedSink bufferedSink = Okio.buffer(countingSink);
mRequestBody.writeTo(bufferedSink);
bufferedSink.flush();
}
protected final class CountingSink extends ForwardingSink{
private long byteWrite;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
byteWrite+=byteCount;
mProgressListener.OnProgress(byteWrite,contentLength());
}
}
}