社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
打个广告,不了解OkHttp的话可以先看下
http://blog.csdn.net/brycegao321/article/details/51830525
需求:
手机拍摄若干张照片, 在wifi连接下上传到服务器。
考虑问题: 如何设置并发传递多个文件的数量? 先剧透一下, OkHttp默认支持并发5个相同ip地址的上传文件请求。
OkHttp是通过 client.newCall(request).enqueue函数添加异步任务的, newCall函数从字面上就看出是创建一个Call实例, 而类Call是OkHttp的执行单元, 即每个Http请求/返回都是一个Call对象。
/** * A call is a request that has been prepared for execution. A call can be * canceled. As this object represents a single request/response pair (stream), * it cannot be executed twice. */再看看enqueue函数(线程安全的哦)做了什么:
public void enqueue(Callback responseCallback) { enqueue(responseCallback, false); } void enqueue(Callback responseCallback, boolean forWebSocket) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } client.getDispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket)); }Dispatcher是OkHttp的调度策略类(Policy on when async requests are executed), 跟进去看Dispatcher的enqueue函数:
synchronized void enqueue(AsyncCall call) { if (runningCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningCalls.add(call); getExecutorService().execute(call); } else { readyCalls.add(call); } }我们看到这里的maxRequests(默认64)和maxRequestsPerHost(默认5)变量, 从英文字面上也能理解出来是最大连接数和同host的最大连接数, 而runningCalls是正在执行的请求, readyCalls是等待执行的请求。getExecutorService().execute(call)是真正的执行http交互。
private int maxRequests = 64; private int maxRequestsPerHost = 5;
背景知识:上传文件的http协议使用了multipart(一般上传文件都使用这种格式, 报文格式可以百度下, 刚好公司服务器down掉了, 没法抓包。。。)的方式传输文件字节流, 稍后会贴出相应代码。
第一步: 就是简单的for循环封装各个文件传输时的参数, 例如文件名、经纬度、用户名之类的, 后台会存到数据库;
for (int i = 0; i < list.size(); i++) { Photo bean = list.get(i); String filePath = bean.getUrl(); if (filePath != null && bean.getStatus() == 0) { if (filePath.startsWith("file://")) filePath = filePath.replace("file://", ""); File file = new File(filePath); if (!file.exists() || file.isDirectory()) { conitue; } Map<String, Object> map = new HashMap<>(); map.put("userid", bean.getUserId());
NetworkUtils.uploadProgressFile(mContext, ConstantUrls.UPLOAD_IMG, callBack
MediaType MEDIA_TYPE_PNG = MediaType.parse("application/octet-stream"); RequestBody requestBody = new MultipartBuilder() .type(MultipartBuilder.FORM) .addFormDataPart("body", JSON.toJSONString(body)) .addFormDataPart("base", base) .addPart(Headers.of("Content-Disposition", "form-data; name="datums" ;filename="" + fileName + """), createUploadRequestBody(MEDIA_TYPE_PNG, file, uploadListener, i)) .build();
public static RequestBody createUploadRequestBody(final MediaType contentType, final File file, final ProgressListener listener, final int position) { return new RequestBody() { @Override public MediaType contentType() { return contentType; } @Override public long contentLength() { return file.length(); } @Override public void writeTo(BufferedSink sink) throws IOException { Source source; try { source = Okio.source(file); Buffer buf = new Buffer(); long contentLength = contentLength(); long currentBytes = 0; for (long readCount; (readCount = source.read(buf, 2048)) != -1; ) { sink.write(buf, readCount); currentBytes += readCount; if (listener != null) { listener.onProgress(currentBytes, contentLength, currentBytes == contentLength, position); } } } catch (Exception e) { // e.printStackTrace(); } } }; }
我们看到使用OkHttp并发传输文件的代码很简单, 就是封装请求后扔到OkHttp的队列里, UI响应回调函数就可以了。
我的微信公众号, 欢迎关注, 让我们一起成长
补充下载文件示例代码:
public interface ICallBack {
void onUploadSuccess(String path); //通知成功,并返回文件位置
void onUploadFailure(); //失败
void onUploadProgress(int current, int total); //上传进度
}
public boolean downLoadFile(String fileUrl, String filePath, final ICallBack callBack) {.... //回调通知失败, 当前是在子线程
callBack.onUploadFailure();
}fos.close();
}
} catch (IOException e) {如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!