一,文件上传
1. MainActivity中的应用
package com.darren.architect_day27;
import android.Manifest;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import com.tbruyelle.rxpermissions2.RxPermissions;
import java.io.File;
import java.io.IOException;
import java.net.FileNameMap;
import java.net.URLConnection;
import io.reactivex.functions.Consumer;
import okhttp3.Call;
import okhttp3.Callback;
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);
// rxPermission
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions.request(Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if(aBoolean){
// 权限申请,并且用户给了权限
uploadFile();
}
}
});
}
private void uploadFile() {
// 这个是 Okhttp 上传文件的用法
String url = "https://api.saiwuquan.com/api/upload";
File file = new File(Environment.getExternalStorageDirectory(), "test.apk");
OkHttpClient httpClient = new OkHttpClient();
// 构建请求 Body , 这个我们之前自己动手写过
MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
builder.addFormDataPart("platform", "android");
builder.addFormDataPart("file", file.getName(),
RequestBody.create(MediaType.parse(guessMimeType(file.getAbsolutePath())), file));
ExMultipartBody exMultipartBody = new ExMultipartBody(builder.build()
,new UploadProgressListener(){
@Override
public void onProgress(long total, long current) {
showToast(total,current);
}
});
// 怎么监听上传文件的进度?
// 构建一个请求
final Request request = new Request.Builder()
.url(url)
.post(exMultipartBody).build();
// new RealCall 发起请求
Call call = httpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("TAG", response.body().string());
}
});
}
private void showToast(final long total, final long current) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//Toast.makeText(MainActivity.this,current+"/"+total,Toast.LENGTH_LONG).show();
}
});
}
private String guessMimeType(String filePath) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String mimType = fileNameMap.getContentTypeFor(filePath);
if(TextUtils.isEmpty(mimType)){
return "application/octet-stream";
}
return mimType;
}
}
2. 静态代理
package com.darren.architect_day27;
import android.support.annotation.Nullable;
import android.util.Log;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
/**
* 静态代理设计模式 implements Target
* Created by hcDarren on 2017/11/25.
*/
public class ExMultipartBody extends RequestBody {
private RequestBody mRequestBody;
private int mCurrentLength;
private UploadProgressListener mProgressListener;
public ExMultipartBody(MultipartBody requestBody) {
this.mRequestBody = requestBody;
}
public ExMultipartBody(MultipartBody requestBody, UploadProgressListener progressListener) {
this.mRequestBody = requestBody;
this.mProgressListener = progressListener;
}
@Nullable
@Override
public MediaType contentType() {
// 静态代理最终还是调用的代理对象的方法
return mRequestBody.contentType();
}
@Override
public long contentLength() throws IOException {
return mRequestBody.contentLength();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Log.e("TAG","监听");
// 总的长度
final long contentLength = contentLength();
// 获取当前写了多少数据?BufferedSink Sink(okio 就是 io )就是一个 服务器的 输出流,我还是不知道写了多少数据
// 又来一个代理 ForwardingSink
ForwardingSink forwardingSink = new ForwardingSink(sink) {
@Override
public void write(Buffer source, long byteCount) throws IOException {
// 每次写都会来这里
mCurrentLength += byteCount;
if(mProgressListener!=null){
mProgressListener.onProgress(contentLength,mCurrentLength);
}
Log.e("TAG",contentLength+" : "+mCurrentLength);
super.write(source, byteCount);
}
};
// 转一把
BufferedSink bufferedSink = Okio.buffer(forwardingSink);
mRequestBody.writeTo(bufferedSink);
// 刷新,RealConnection 连接池
bufferedSink.flush();
}
}
3.回调接口
package com.darren.architect_day27;
/**
* Created by hcDarren on 2017/11/25.
*/
public interface UploadProgressListener {
void onProgress(long total,long current);
}
二,OkHttp自定义缓存拦截
1. MainActivity中的应用
package com.darren.architect_day27.simple2;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.darren.architect_day27.R;
import java.io.File;
import java.io.IOException;
import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
private OkHttpClient mHttpClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 自定义缓存(要求:有网 30s 内请求读缓存,无网直接读缓存)
// OkHttp 自带的扩展有坑,我们之前自己写过这个缓存管理,与 OkHttp 结合就可以了
// 思路?拦截器?分为两种
File file = new File(Environment.getExternalStorageDirectory(),"cache");
Cache cache = new Cache(file,100*1024*1024);
mHttpClient = new OkHttpClient.Builder()
.cache(cache)
// 加载最前 过期时间缓存多少秒 没网读缓存
.addInterceptor(new CacheRequestInterceptor(this))
// 加载最后,数据缓存 过期时间 30s 对Response的操作
.addNetworkInterceptor(new CacheResponseInterceptor())
.build();
}
public void click(View view){
String url = "https://api.saiwuquan.com/api/appv2/sceneModel";
// 构建一个请求
final Request request = new Request.Builder()
.url(url).build();
// new RealCall 发起请求
Call call = mHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("TAG",response.body().string());
// 都是有 第一把,第二把没有网络的了只有缓存的 (30s 以内),过了 30s 之后又会有网络的了(会再请求更新)
Log.e("TAG", response.cacheResponse()+" ; "+response.networkResponse());
}
});
}
}
2. 放在ConnectInterceptor 和 CallServerInterceptor 之间的自定义拦截器,设置缓存保持为3.秒
package com.darren.architect_day27.simple2;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Response;
/**
* Created by hcDarren on 2017/11/25.
*/
public class CacheResponseInterceptor implements Interceptor{
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// 过期时间是 30s
response = response.newBuilder()
.removeHeader("Cache-Control")
.removeHeader("Pragma")
.addHeader("Cache-Control","max-age="+30).build();
return response;
}
}
3. 放在retryAndFollowUpInterceptor 之前 自定义缓存拦截器,设定为有网就30秒缓存,过期就重新请求网络,没有过期就读取缓存。如果没有网络,就直接读取缓存。
package com.darren.architect_day27.simple2;
import android.content.Context;
import java.io.IOException;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by hcDarren on 2017/11/25.
*/
public class CacheRequestInterceptor implements Interceptor{
private Context mContext;
public CacheRequestInterceptor(Context context){
this.mContext = context;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if(isNetWork(mContext)){
// 只读缓存
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE).build();
}
return chain.proceed(request);
}
private boolean isNetWork(Context mContext) {
// 自己去完善
return true;
}
}