上传进度的实现
首先简单使用
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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 = "http://192.168.56.1:8080/FileUpload/FileUploadServlet";
File file=new File(Environment.getExternalStorageDirectory()+"/Download/","logo.jpg");
OkHttpClient httpClient=new OkHttpClient();
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));
Request request=new Request.Builder().url(url).post(builder.build()).build();
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 String guessMimeType(String filePath) {
FileNameMap fileNameMap= URLConnection.getFileNameMap();
String mimType = fileNameMap.getContentTypeFor(filePath);
if(TextUtils.isEmpty(mimType)){
return "application/octet-stream";
}
return mimType;
}
}
分析很简单,okhttp上传进度实际也是写数据,向服务器写,其拦截器是CallServerInterceptor拦截器
// 写数据,表单数据,文件,实际是MultipartBody的writeTo写数据的方法
request.body().writeTo(bufferedRequestBody);
所以根据上面分析,我们可以用一个类去继承于MultipartBody复写其中的方法,但是这时候我们继承不了,因为这里MultipartBody是final类,这时候可以使用静态代理的方法
public class ExMultipartBody extends RequestBody {
private RequestBody mRequestBody;
private long mCurrentLength;
private UploadProgressListener mProgressListener;
public ExMultipartBody(MultipartBody body, UploadProgressListener uploadProgressListener) {
this.mRequestBody = body;
this.mProgressListener = uploadProgressListener;
}
@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();
//写了多少条数据
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);
//刷新一下,否则会发现上传不成功
bufferedSink.flush();
}
}
UploadProgressListener进度接口
public interface UploadProgressListener {
void onProgress(long total,long current);
}
修改MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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";
String url = "http://192.168.56.1:8080/FileUpload/FileUploadServlet";
File file=new File(Environment.getExternalStorageDirectory()+"/Download/","logo.jpg");
OkHttpClient httpClient=new OkHttpClient();
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);
}
});
Request request=new Request.Builder().url(url).post(exMultipartBody).build();
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;
}
}
自定义缓存(要求:有网 30s 内请求读缓存,无网直接读缓存)
思路分析:在最后添加一个拦截器,移除response的头部Cache-Control字段,并重新添加字段且设置max-age为30,在拦截器最前面添加拦截器,无网的情况设置request为仅缓存
CacheResponseInterceptor,设置有网30s内请求读缓存
public class CacheResponseInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
response=response.newBuilder()
.removeHeader("Cache-Control")
//max-age既有缓存策略也有过期时间
.addHeader("Cache-Control","max-age="+30).build();
return response;
}
}
CacheRequestInterceptor无网直接读取缓存
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()) {
//只读缓存
/* request.newBuilder()
.cacheControl(new CacheControl.Builder().onlyIfCached().build());*/
request.newBuilder().cacheControl(CacheControl.FORCE_CACHE);
}
return chain.proceed(request);
}
public boolean isNetWork() {
NetworkInfo info = getNetworkInfo(mContext);
if (info != null) {
return info.isAvailable();
}
return false;
}
private static NetworkInfo getNetworkInfo(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo();
}
}
MainActivity代码
// 自定义缓存(要求:有网 30s 内请求读缓存,无网直接读缓存)
public void click(View view) {
// 这个是 Okhttp 上传文件的用法
String url = "http://zs.ahhuabang.com:8088/zhushou/public/index.php/index/user/deal_order?page=1&page_size=1";
File file=new File(Environment.getExternalStorageDirectory(),"cache");
Cache cache=new Cache(file,1024*1024*100);
OkHttpClient httpClient = new OkHttpClient.Builder()
.cache(cache)
//添加拦截器在最前面
.addInterceptor(new CacheRequestInterceptor(this))
//加载最后,数据缓存 过期时间 30s
.addNetworkInterceptor(new CacheResponseInterceptor())
.build();
Request request = new Request.Builder().url(url).build();
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());
Log.e("TAG", response.cacheResponse() + " ; " + response.networkResponse());
}
});
}