1.OkHttp什么是什么?
OkHttp是一款优秀的HTTP框架,它支持get请求和post请求,支持基于Http的文件上传和下载,支持加载图片,支持下载文件透明的GZIP压缩,支持响应缓存避免重复的网络请求,支持使用连接池来降低响应延迟问题。OkHttp官网
2.怎么使用?
1.在app的build.gradle中添加OkHttp的依赖
compile 'com.squareup.okhttp3:okhttp:3.11.0'
2.AndroidManifest.xml中加入网络权限
<uses-permission android:name="android.permission.INTERNET"/>
3.具体使用步骤
步骤1:拿到OkHttpClient对象
步骤2:构造Request
步骤3:将Request封装为Call
步骤4:执行Call
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*解决session过期问题*/
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
private Map<String, List<Cookie>> cookieStore = new HashMap<>();
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url.host(), cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
}).build();
}
//1.拿到OkHttpClient对象
OkHttpClient okHttpClient = new OkHttpClient();
public void doGet(View view) throws IOException {
//2.构造Request
Request.Builder builder = new Request.Builder();
Request request = builder.get().url("https://www.imooc.com/").build();
executeRequest(request);
}
private void executeRequest(Request request) {
//3.将Request封装为Call
Call call = okHttpClient.newCall(request);
//4.执行Call
//同步执行请求,发送请求后,就会进入阻塞状态,直到收到响应,
//所以必须在子线程中执行,否则或抛出android.os.NetworkOnMainThreadException异常
//Response response = call.execute();
//异步执行请求,请求放到线程池队列中等待执行,执行完成后在Callback回调中进行响应数据的处理,注意回调是在子线程
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
runOnUiThread(new Runnable() {
@Override
public void run() {
//更新UI操作
String responseString = null;
try {
responseString = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
Log.d("onResponse",responseString);
}
});
}
});
}
//要提交post请求的url,这里是瞎写的,不可用
private String mBaseUrl = "www.post.com";
public void doPost(View view){
//2.构造Request
//2.1构造requestBody
FormBody.Builder formBodeBuilder = new FormBody.Builder();
RequestBody requestBody = formBodeBuilder.add("username", "test")
.add("password", "test")
.build();
Request.Builder builder = new Request.Builder();
Request request = builder.url(mBaseUrl + "login").post(requestBody).build();
executeRequest(request);
}
//post提交字符串
public void doPostString(View view){
RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;chaset=utf-8"), "testString");
Request.Builder builder = new Request.Builder();
Request request = builder.url(mBaseUrl + "postString").post(requestBody).build();
executeRequest(request);
}
//post提交文件
//写文件要添加WRITE_EXTERNAL_STORAGE权限
public void doPostFile(View view){
File file = new File(Environment.getExternalStorageDirectory(),"test.jpg");
if (!file.exists()){
Log.e("mTAG",file.getAbsolutePath()+"not exist!");
return;
}
//不知道数据的具体MediaType,可以搜索mime type去查找
RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
Request.Builder builder = new Request.Builder();
Request request = builder.url(mBaseUrl + "postString").post(requestBody).build();
executeRequest(request);
}
//post上传文件
public void doUpload(View view){
File file = new File(Environment.getExternalStorageDirectory(),"test.jpg");
if (!file.exists()){
Log.e("mTAG",file.getAbsolutePath()+"not exist!");
return;
}
MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
RequestBody requestBody = multipartBodyBuilder.setType(MultipartBody.FORM)
.addFormDataPart("username", "test")
.addFormDataPart("password", "test")
//addFormDataPart(服务器表单域key,服务器图片名称,File的RequestBody)
.addFormDataPart("mPhoto", "upload.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
Request.Builder builder = new Request.Builder();
Request request = builder.url(mBaseUrl + "uploadInfo").post(requestBody).build();
executeRequest(request);
}
//post下载文件
public void doDownload(View view){
//2.构造Request
Request.Builder builder = new Request.Builder();
Request request = builder.get().url(mBaseUrl+"files/test.jpg").build();
//3.将Request封装为Call
Call call = okHttpClient.newCall(request);
//4.执行Call
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
InputStream is = response.body().byteStream();
int len = 0;
File file = new File(Environment.getExternalStorageDirectory(),"test1.jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[128];
while ((len = is.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.flush();
fos.close();
is.close();
runOnUiThread(new Runnable() {
@Override
public void run() {
//更新UI操作
/*对于大图片可以先将图片下载到本地,
利用BitmapFactory.Options将图片进行改造压缩。
inJustDecodeBounds
inSampleSize
然后再显示
*/
}
});
}
});
}
}
2.追踪下载和上传文件进度
2.1 追踪下载进度的方法(在写文件方面做文章)
//post下载文件,在上面代码doDownload方法的基础上做修改
public void doDownload(View view){
//2.构造Request
Request.Builder builder = new Request.Builder();
Request request = builder.get().url(mBaseUrl+"files/test.jpg").build();
//3.将Request封装为Call
Call call = okHttpClient.newCall(request);
//4.执行Call
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
long total = response.body().contentLength();
long sum = 0L;
InputStream is = response.body().byteStream();
int len = 0;
File file = new File(Environment.getExternalStorageDirectory(),"test1.jpg");
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[128];
while ((len = is.read(buf))!=-1){
fos.write(buf,0,len);
sum += len;
//通过日志打印出下载进度
Log.d("progress",sum + "/" + total);
}
fos.flush();
fos.close();
is.close();
}
});
}
2.2 通过对原有的RequestBody进行封装的方法来追踪上传进度。
创建ProgressResponseBody,继承自RequestBody
import android.support.annotation.Nullable;
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;
public class ProgressRequestBody extends RequestBody {
//真正的RequestBody,内部所有的方法都是通过这个代理对象去执行
private RequestBody delegateRequestBody;
private ProgressListener listener;
public interface ProgressListener {
/**
* @param byteWrited 上传了的字节数
* @param total 总共的字节数
*/
void onUploadProgress(long byteWrited,long total);
}
public ProgressRequestBody(RequestBody delegateRequestBody, ProgressListener listener) {
this.delegateRequestBody = delegateRequestBody;
this.listener = listener;
}
@Nullable
@Override
public MediaType contentType() {
return delegateRequestBody.contentType();
}
@Override
public long contentLength() {
try {
return delegateRequestBody.contentLength();
} catch (IOException e) {
return -1;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
CountingSink countingSink = new CountingSink(sink);
BufferedSink bufferedSink = Okio.buffer(countingSink);
delegateRequestBody.writeTo(bufferedSink);
bufferedSink.flush();
}
private class CountingSink extends ForwardingSink{
private long bytesWrited;
public CountingSink(Sink delegate) {
super(delegate);
}
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
bytesWrited += byteCount;
listener.onUploadProgress(bytesWrited,contentLength());
}
}
}
使用ProgressRequestBody追踪上传进度
//post上传文件
public void doUpload(View view){
File file = new File(Environment.getExternalStorageDirectory(),"test.jpg");
if (!file.exists()){
Log.e("mTAG",file.getAbsolutePath()+"not exist!");
return;
}
MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
RequestBody requestBody = multipartBodyBuilder.setType(MultipartBody.FORM)
.addFormDataPart("username", "test")
.addFormDataPart("password", "test")
//addFormDataPart(服务器表单域key,服务器图片名称,File的RequestBody)
.addFormDataPart("mPhoto", "upload.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
//使用我们封装的ProgressRequestBody
ProgressRequestBody progressRequestBody = new ProgressRequestBody(requestBody, new ProgressRequestBody.ProgressListener() {
@Override
public void onUploadProgress(long byteWrited, long total) {
//通过日志打印出上传进度
Log.d("progress",byteWrited + "/" + total);
}
});
Request.Builder builder = new Request.Builder();
Request request = builder.url(mBaseUrl + "uploadInfo").post(progressRequestBody).build();
executeRequest(request);
}
3.封装
实际开发中建议使用封装的比较好的OkHttp库OkGo:https://github.com/jeasonlzy/okhttp-OkGo。
网友评论