对RxJava2+Retrofit2+OkHttp3的封装,优雅实现接口请求和文件下载
- 网络请求(RxRequest)
- 支持监听请求声明周期,如开始结束和网络错误
- 支持多BaseUrl,可针对不同请求重定向
- 支持针对不同请求设置不同缓存策略,如无网强制获取缓存,有网缓存有效10秒
- 支持添加公共请求参数
- 支持自定义异常处理和异常提示消息
- 文件下载(RxDownload)
- 支持断点续传
- 支持下载进度回调
- 支持下载速度回调
- 支持下载过程状态监听
- 支持在仅保存下载路径未保存进度时自动恢复断点续传
- 支持自动获取真实文件名
- 新建网络请求配置类继承RequestSetting或DefaultRequestSetting,并复写部分方法。
publicclassRxHttpRequestSettingextendsDefaultRequestSetting {
@NonNull@OverridepublicStringgetBaseUrl() {
returnConfig.BASE_URL;
}
@OverridepublicintgetSuccessCode() {
return200;
}
}- 在Application中初始化并传入配置类实例
RxHttp.init(this);
RxHttp.initRequest(newRxHttpRequestSetting());publicclassPublicHeadersInterceptorimplementsInterceptor {
privatestaticStringTIME = "";
privatestaticStringTOKEN = "";
publicstaticvoidupdateTime(Stringtime) {
PublicHeadersInterceptor.TIME = time;
}
publicstaticvoidupdateToken(Stringtoken) {
PublicHeadersInterceptor.TOKEN = token;
}
@OverridepublicResponseintercept(Chainchain) throwsIOException {
Requestrequest = chain.request();
request = request.newBuilder()
.header(Constant.PUBLIC_HEADER_TIME_NAME, TIME)
.header(Constant.PUBLIC_HEADER_SIGN_NAME, getSign(request))
.build();
returnchain.proceed(request);
}
privateStringgetSign(Requestrequest){
returnMD5Coder.encode(request.url().url().toString() + "?token=" + TOKEN);
}
}publicclassPublicParamsInterceptorimplementsInterceptor {
privatestaticfinalStringGET = "GET";
privatestaticfinalStringPOST = "POST";
@OverridepublicResponseintercept(Chainchain) throwsIOException {
Requestrequest = chain.request();
Stringmethod = request.method();
if (TextUtils.equals(method, GET)) {
request = addForGet(request);
} elseif (TextUtils.equals(method, POST)) {
request = addForPost(request);
}
returnchain.proceed(request);
}
privateRequestaddForGet(Requestrequest) {
List<Param> params = getPublicParams();
HttpUrlhttpUrl = request.url();
HttpUrl.BuilderhttpUrlBuilder = httpUrl.newBuilder();
for (inti = 0; i < httpUrl.querySize(); i++) {
Stringname = httpUrl.queryParameterName(i);
Stringvalue = httpUrl.queryParameterValue(i);
params.add(newParam(name, value));
httpUrlBuilder.removeAllQueryParameters(name);
}
JsonObjUtilsjson = JsonObjUtils.create();
for (Paramparam : params) {
json.add(param.getKey(), param.getValue());
}
LogUtils.i("PublicParamsInterceptor", "data=" + json.toJson());
httpUrlBuilder.setQueryParameter(Constant.PUBLIC_PARAM_KEY, json.toJson());
returnrequest.newBuilder()
.url(httpUrlBuilder.build())
.build();
}
privateRequestaddForPost(Requestrequest) {
RequestBodyrequestBody = request.body();
if (requestBody == null) {
returnrequest;
} elseif (requestBodyinstanceofFormBody) {
List<Param> params = getPublicParams();
FormBodyformBody = (FormBody) requestBody;
for (inti = 0; i < formBody.size(); i++) {
params.add(newParam(formBody.name(i), formBody.value(i)));
}
JsonObjUtilsjson = JsonObjUtils.create();
for (Paramparam : params) {
json.add(param.getKey(), param.getValue());
}
LogUtils.i("PublicParamsInterceptor", "data=" + json.toJson());
FormBody.BuilderformBodyBuilder = newFormBody.Builder()
.add(Constant.PUBLIC_PARAM_KEY, json.toJson());
returnrequest.newBuilder()
.post(formBodyBuilder.build())
.build();
} elseif (requestBodyinstanceofMultipartBody) {
returnrequest;
} else {
try {
if (requestBody.contentLength() == 0) {
List<Param> params = getPublicParams();
JsonObjUtilsjson = JsonObjUtils.create();
for (Paramparam : params) {
json.add(param.getKey(), param.getValue());
}
LogUtils.i("PublicParamsInterceptor", "data=" + json.toJson());
FormBody.BuilderformBodyBuilder = newFormBody.Builder()
.add(Constant.PUBLIC_PARAM_KEY, json.toJson());
returnrequest.newBuilder()
.post(formBodyBuilder.build())
.build();
} else {
returnrequest;
}
} catch (IOExceptione) {
returnrequest;
}
}
}
privateList<Param> getPublicParams() {
List<Param> params = newArrayList<>();
params.add(newParam(Constant.PUBLIC_PARAM_SYSTEM_KEY, Constant.PUBLIC_PARAM_SYSTEM_VALUE));
params.add(newParam(Constant.PUBLIC_PARAM_VERSION_KEY, String.valueOf(AppInfoUtils.getVersionCode())));
params.add(newParam(Constant.PUBLIC_PARAM_USER_ID_KEY, UserUtils.getInstance().getUserId()));
params.add(newParam(Constant.PUBLIC_PARAM_USER_DEVICE_KEY, DeviceIdUtils.getId()));
params.add(newParam(Constant.PUBLIC_PARAM_JPUSH_DEVICE_KEY, JPushHelper.getId()));
returnparams;
}
}定义ResponseBean< E >继承BaseResponse< E >,定义成员变量并实现方法。
publicclassResponseBean<E> implementsBaseResponse<E> {
@SerializedName(value = "code"/*, alternate = {"status"}*/)
privateintcode;
@SerializedName(value = "data"/*, alternate = {"result"}*/)
privateEdata;
@SerializedName(value = "msg"/*, alternate = {"message"}*/)
privateStringmsg;
@OverridepublicintgetCode() {
returncode;
}
@OverridepublicvoidsetCode(intcode) {
this.code = code;
}
@OverridepublicEgetData() {
returndata;
}
@OverridepublicvoidsetData(Edata) {
this.data = data;
}
@OverridepublicStringgetMsg() {
returnmsg;
}
@OverridepublicvoidsetMsg(Stringmsg) {
this.msg = msg;
}
}publicclassTimeBeanextendsBaseBean {
privateStringtoken;
privateStringtime;
publicStringgetToken() {
returntoken;
}
publicvoidsetToken(Stringtoken) {
this.token = token;
}
publicStringgetTime() {
returntime;
}
publicvoidsetTime(Stringtime) {
this.time = time;
}
}- 新建子类继承自Api
- 定义一个内部类Service声明请求
- 定义静态无参方法返回Api.api(Service.class)创建Api实例
publicclassFreeApiextendsApi {
publicstaticServiceapi() {
returnApi.api(Service.class);
}
publicinterfaceConfig {
StringBASE_URL = Config.HTTP_HOST + Config.HTTP_VERSION;
longHTTP_TIMEOUT = 5000;
}
publicinterfaceCode{
intTIME_OUT = 1000; // 请求延迟intREQUEST_ERROR = 1001; // 请求方式错误intILLEGAL_PARAMETER = 1002; // 非法参数intSUCCESS = 2000; // 获取信息成功intSUCCESS_OLD = 104; // 获取信息成功 老版本的intSUCCESS_NO_DATA = 2001; // 暂无相关数据intFAILED = 3000; // 获取信息失败intPHONE_EXIST = 3001; // 该手机号已注册过intPASSWARD_ERROR = 3002; // 密码错误intPHONE_ILLEGAL = 3003; // 手机号不合法intPHONE_NOT_BIND = 3004; // 请绑定手机号intPHONE_NOT_REGIST = 3005; // 该手机号未注册intACCOUNT_NOT_EXIST = 4001; // 账号不存在intACCOUNT_EXCEPTION = 4002; // 账号异常,请重新登录intACCOUNT_FROZEN = 4003; // 该账户已被冻结,请联系管理员intACCOUNT_DELETED = 4004; // 该账户已被管理员删除intERROR = 5000; // 访问异常intERROR_NET = 5001; // 网络异常
}
publicinterfaceService {
@GET("public/time")
Observable<ResponseBean<TimeBean>> getTime();
}
}publicinterfaceRequestBackListener<T> {
voidonStart();
voidonSuccess(intcode, Tdata);
voidonFailed(intcode, Stringmsg);
voidonNoNet();
voidonError(Throwablee);
voidonFinish();
}封装签名的获取和响应回调的处理逻辑。
在调用正式接口之前,我们可能需要先调用一个获取时间戳的接口,将时间戳接口返回的时间戳和签名字段添加到正式接口的公共参数或请求头中,才能发起正式请求。所以在该基类中进行封装,抽取公共代码。
如果时间戳接口返回了版本更新字段,需要版本号等判断请求的执行流程,如强制更新且不需要继续执行正式接口,可在此处自行处理。
publicclassBaseRequest {
protectedstatic <T> DisposablerequestWithSign(@NonNullRequestCallback<T> observable, @NonNullRequestBackListener<T> callback) {
returnrequest(ProjectApi.api().getTime()
.flatMap(newFunction<ResponseBean<TimeBean>, ObservableSource<ResponseBean<T>>>() {
@OverridepublicObservable<ResponseBean<T>> apply(ResponseBean<TimeBean> bean) {
PublicHeadersInterceptor.updateTime(bean.getData().getTime());
PublicHeadersInterceptor.updateToken(bean.getData().getToken());
returnobservable.request().subscribeOn(Schedulers.io());
}
}), callback);
}
protectedstatic <T> Disposablerequest(@NonNullObservable<ResponseBean<T>> observable, @NonNullRequestBackListener<T> callback) {
returnRxRequest.create(observable)
.listener(newRxRequest.RequestListener() {
@OverridepublicvoidonStart() {
callback.onStart();
}
@OverridepublicvoidonError(ExceptionHandlehandle) {
handle.getException().printStackTrace();
if (handle.getCode() == ExceptionHandle.Code.NET) {
ToastMaker.showShort(R.string.http_no_net);
callback.onNoNet();
callback.onFailed(ProjectApi.Code.ERROR_NET, ResUtils.getString(R.string.http_no_net));
} else {
callback.onError(handle.getException());
callback.onFailed(ProjectApi.Code.ERROR, ResUtils.getString(R.string.http_error));
}
}
@OverridepublicvoidonFinish() {
callback.onFinish();
}
})
.request(newRxRequest.ResultCallback<T>() {
@OverridepublicvoidonSuccess(intcode, Tdata) {
callback.onSuccess(code, data);
}
@OverridepublicvoidonFailed(intcode, Stringmsg) {
if (code == ProjectApi.Code.ACCOUNT_NOT_EXIST ||
code == ProjectApi.Code.ACCOUNT_EXCEPTION ||
code == ProjectApi.Code.ACCOUNT_FROZEN ||
code == ProjectApi.Code.ACCOUNT_DELETED) {
ForceOfflineReceiver.send(code, msg);
}
callback.onFailed(code, msg);
}
});
}
protectedinterfaceRequestCallback<T> {
Observable<ResponseBean<T>> request();
}
}publicclassPublicRequestextendsBaseRequest {
/** * 获取系统时间 */publicstaticDisposablegetTime(finalRequestBackListener<TimeBean> listener) {
returnrequest(ProjectApi.api().getTime(), listener);
}
/** * 获取反馈类型 */publicstaticDisposableother(finalRequestBackListener<OtherBean> listener) {
returnrequestWithSign(newRequestCallback<OtherAean>() {
@OverridepublicObservable<ResponseBean<OtherBean>> request() {
returnProjectApi.api().otherApi();
}
}, listener);
}
}你可以在Activity或者Fragment中发起请求,也可以在你的Presenter层中发起请求,只需要注意请求生命周期的管理。
使用时分为3步处理:
- 在onCreate方法中(如果是Presenter中使用应该在其绑定到视图时)调用RxLife.create()方法,该方法会返回一个RxLife实例mRxLife。
- 在onDestroy方法中(如果是Presenter中使用应该在其从视图解除绑定时)调用mRxLife.destroy()方法,该方法会自动中断所有未完成的请求,防止内存泄漏。
- 发起一个请求,并调用mRxLife.add(Disposable)添加至管理队列。
下面将以MVP模式进行举例说明。
- 在P层基类中添加RxLife的创建和销毁,并提供addToRxLife方法。
publicabstractclassMvpPresenter<VextendsMvpView> {
protectedContextcontext;
privateVbaseView;
privateRxLiferxLife;
voidonCreate(VbaseView) {
this.baseView = baseView;
context = baseView.getContext();
rxLife = RxLife.create();
}
voidonDestroy() {
baseView = null;
context = null;
rxLife.destroy();
rxLife = null;
}
publicRxLifegetRxLife() {
returnrxLife;
}
publicvoidaddToRxLife(Disposabledisposable) {
if (rxLife != null) {
rxLife.add(disposable);
}
}
publicVgetBaseView() {
returnbaseView;
}
publicbooleanisAttachView() {
returnbaseView != null;
}
publicContextgetContext() {
returncontext;
}
}- 新建P层,发起请求。
publicclassOtherPresenterextendsMvpPresenter<FeedbackView> {
publicvoidother() {
addToRxLife(PublicRequest.other(newRequestBackListener<OtherBean>() {
@OverridepublicvoidonStart() {
showLoading();
}
@OverridepublicvoidonSuccess(intcode, OtherBeandata) {
if (isAttachView()) {
getBaseView().otherSuccess(code, data);
}
}
@OverridepublicvoidonFailed(intcode, Stringmsg) {
if (isAttachView()) {
getBaseView().otherFail(code, msg);
}
}
@OverridepublicvoidonNoNet() {
}
@OverridepublicvoidonError(Throwablee) {
}
@OverridepublicvoidonFinish() {
dismissLoading();
}
}));
}
}- 新建V层接口,并在Activity或Fragment实现接口回调,进行数据展示。
publicinterfaceOtherViewextendsMvpView {
voidotherSuccess(intcode, OtherBeandata);
voidotherFail(intcode, Stringmsg);
}创建JSONObject对象并生成Json字符串。
创建RequestBody,针对POST请求。
如图片上传接口
/** * 键 值 * img File * content String */@Multipart@POST("public/img")
Observable<ResponseBean<UploadImgBean>> uploadImg(@PartMapMap<String, RequestBody> img);发起请求如下
publicstaticDisposableuploadImg(Stringcontent, FileimgFile, finalRequestBackListener<UploadImgBean> listener) {
returnrequestWithSign(newRequestCallback<UploadImgBean>() {
@OverridepublicObservable<ResponseBean<UploadImgBean>> request() {
Map<String, RequestBody> map = RequestBodyUtils.builder()
.add("content", content)
.add("img", imgFile)
.build();
returnProjectApi.api().uploadImg(map);
}
}, listener);
}主要提供7个静态方法,用于实现证书忽略和开启Android4.4及以下对TLS1.2的支持。
/** * 忽略证书的验证,这样请求就和HTTP一样,失去了安全保障,不建议使用 */publicstaticvoidignoreSSLForOkHttp(OkHttpClient.Builderbuilder)
/** * 开启HttpsURLConnection对TLS1.2的支持 */publicstaticvoidenableTls12ForOkHttp(OkHttpClient.Builderbuilder)
/** * 忽略证书的验证,这样请求就和HTTP一样,失去了安全保障,不建议使用 * 应在使用HttpsURLConnection之前调用,建议在application中 */publicstaticvoidignoreSSLForHttpsURLConnection()
/** * 开启HttpsURLConnection对TLS1.2的支持 * 应在使用HttpsURLConnection之前调用,建议在application中 */publicstaticvoidenableTls12ForHttpsURLConnection()
/** * 获取开启TLS1.2的SSLSocketFactory * 建议在android4.4及以下版本调用 */publicstaticSSLSocketFactorygetEnableTls12SSLSocketFactory()
/** * 获取忽略证书的HostnameVerifier * 与{@link #getIgnoreSSLSocketFactory()}同时配置使用 */publicstaticHostnameVerifiergetIgnoreHostnameVerifier()
/** * 获取忽略证书的SSLSocketFactory * 与{@link #getIgnoreHostnameVerifier()}同时配置使用 */publicstaticSSLSocketFactorygetIgnoreSSLSocketFactory()官方资料在框架安全性变更提及,如果应用以 Android 9 或更高版本为目标平台则默认情况下启用网络传输层安全协议 (TLS),即 isCleartextTrafficPermitted() 函数返回 false。 如果您的应用需要为特定域名启用明文,您必须在应用的网络安全性配置中针对这些域名将 cleartextTrafficPermitted 显式设置为 true。
因此解决办法有2种:
第一种,启用HTTP,允许明文传输(不建议采用)
- 在资源文件夹res/xml下面创建network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-configcleartextTrafficPermitted="true">
<trust-anchors>
<certificatessrc="system" />
</trust-anchors>
</base-config>
</network-security-config>- 在清单文件AndroidManifest.xml的application标签里面设置networkSecurityConfig属性引用。
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<applicationandroid:networkSecurityConfig="@xml/network_security_config">
</application>
</manifest>第二种,所有接口采用HTTPS协议(建议采用)
此方法需确保后台正确配置,如配置后仍有无法访问,且提示证书异常,请检查后台配置。
该情况一般为后台未正确配置证书。请检查后台配置。
在测试时,我们可以暂时选择忽略证书,这样请求就和HTTP一样,但会失去安全保障,不允许在正式发布时使用。
可直接使用HttpsCompat工具类。
实现代码如下:
publicstaticvoidignoreSSLForOkHttp(OkHttpClient.Builderbuilder) {
builder.hostnameVerifier(getIgnoreHostnameVerifier())
.sslSocketFactory(getIgnoreSSLSocketFactory());
}
publicstaticvoidignoreSSLForHttpsURLConnection() {
HttpsURLConnection.setDefaultHostnameVerifier(getIgnoreHostnameVerifier());
HttpsURLConnection.setDefaultSSLSocketFactory(getIgnoreSSLSocketFactory());
}
/** * 获取忽略证书的HostnameVerifier * 与{@link #getIgnoreSSLSocketFactory()}同时配置使用 */privatestaticHostnameVerifiergetIgnoreHostnameVerifier() {
returnnewHostnameVerifier() {
@Overridepublicbooleanverify(Strings, SSLSessionsslSession) {
returntrue;
}
};
}
/** * 获取忽略证书的SSLSocketFactory * 与{@link #getIgnoreHostnameVerifier()}同时配置使用 */privatestaticSSLSocketFactorygetIgnoreSSLSocketFactory() {
try {
SSLContextsslContext = SSLContext.getInstance("SSL");
sslContext.init(null, getTrustManager(), newSecureRandom());
returnsslContext.getSocketFactory();
} catch (Exceptione) {
thrownewRuntimeException(e);
}
}
privatestaticTrustManager[] getTrustManager() {
returnnewTrustManager[]{
newX509TrustManager() {
@OverridepublicvoidcheckClientTrusted(X509Certificate[] chain, StringauthType) {
}
@OverridepublicvoidcheckServerTrusted(X509Certificate[] chain, StringauthType) {
}
@OverridepublicX509Certificate[] getAcceptedIssuers() {
returnnewX509Certificate[]{};
}
}
};
}服务器已正确配置SSL证书,且已打开TLS1.1和TLS1.2,但是在Android4.4及以下无法访问网络。是因为在Android4.4及以下版本默认不支持TLS1.2,需要开启对TLS1.2的支持。代码如下:
publicstaticvoidenableTls12ForHttpsURLConnection() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
SSLSocketFactoryssl = getEnableTls12SSLSocketFactory();
if (ssl != null) {
HttpsURLConnection.setDefaultSSLSocketFactory(ssl);
}
}
}
publicstaticvoidenableTls12ForOkHttp(OkHttpClient.Builderbuilder) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
SSLSocketFactoryssl = HttpsCompat.getEnableTls12SSLSocketFactory();
if (ssl != null) {
builder.sslSocketFactory(ssl);
}
}
}
publicstaticSSLSocketFactorygetEnableTls12SSLSocketFactory() {
try {
SSLContextsslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
returnnewTls12SocketFactory(sslContext.getSocketFactory());
} catch (Exceptione) {
e.printStackTrace();
}
returnnull;
}
privatestaticclassTls12SocketFactoryextendsSSLSocketFactory {
privatestaticfinalString[] TLS_SUPPORT_VERSION = {"TLSv1.1", "TLSv1.2"};
privatefinalSSLSocketFactorydelegate;
privateTls12SocketFactory(SSLSocketFactorybase) {
this.delegate = base;
}
@OverridepublicString[] getDefaultCipherSuites() {
returndelegate.getDefaultCipherSuites();
}
@OverridepublicString[] getSupportedCipherSuites() {
returndelegate.getSupportedCipherSuites();
}
@OverridepublicSocketcreateSocket(Sockets, Stringhost, intport, booleanautoClose) throwsIOException {
returnpatch(delegate.createSocket(s, host, port, autoClose));
}
@OverridepublicSocketcreateSocket(Stringhost, intport) throwsIOException, UnknownHostException {
returnpatch(delegate.createSocket(host, port));
}
@OverridepublicSocketcreateSocket(Stringhost, intport, InetAddresslocalHost, intlocalPort) throwsIOException, UnknownHostException {
returnpatch(delegate.createSocket(host, port, localHost, localPort));
}
@OverridepublicSocketcreateSocket(InetAddresshost, intport) throwsIOException {
returnpatch(delegate.createSocket(host, port));
}
@OverridepublicSocketcreateSocket(InetAddressaddress, intport, InetAddresslocalAddress, intlocalPort) throwsIOException {
returnpatch(delegate.createSocket(address, port, localAddress, localPort));
}
privateSocketpatch(Sockets) {
if (sinstanceofSSLSocket) {
((SSLSocket) s).setEnabledProtocols(TLS_SUPPORT_VERSION);
}
returns;
}
}原因同上,需要自定义Glide的AppGlideModule,传入支持TLS1.2的OkHttpClient。
@GlideModulepublicclassCustomAppGlideModuleextendsAppGlideModule {
@OverridepublicvoidregisterComponents(@NonNullContextcontext, @NonNullGlideglide, @NonNullRegistryregistry) {
registry.replace(GlideUrl.class, InputStream.class, newOkHttpUrlLoader.Factory(getOkHttpClient()));
}
@OverridepublicbooleanisManifestParsingEnabled() {
returnfalse;
}
privatestaticOkHttpClientgetOkHttpClient() {
OkHttpClient.Builderbuilder = newOkHttpClient.Builder();
HttpsCompat.enableTls12ForOkHttp(builder);
returnbuilder.build();
}
}初始化操作可在Application中也可在应用启动页中进行
RxHttp.init(this);
// 可选,未配置设置将自动采用DefaultDownloadSettingRxHttp.initDownload(newDefaultDownloadSetting() {
@OverridepubliclonggetTimeout() {
return60000;
}
}); RxDownloadmRxDownload = RxDownload.create(et_url.getText().toString())
.setDownloadListener(newRxDownload.DownloadListener() {
@OverridepublicvoidonStarting(DownloadInfoinfo) {
tv_start.setText("正在开始...");
}
@OverridepublicvoidonDownloading(DownloadInfoinfo) {
tv_start.setText("正在下载");
}
@OverridepublicvoidonError(DownloadInfoinfo, Throwablee) {
tv_start.setText("下载失败");
}
@OverridepublicvoidonStopped(DownloadInfoinfo) {
tv_start.setText("已停止");
}
@OverridepublicvoidonCanceled(DownloadInfoinfo) {
tv_start.setText("已取消");
pb_1.setProgress(0);
}
@OverridepublicvoidonCompletion(DownloadInfoinfo) {
tv_start.setText("下载成功");
}
})
.setProgressListener(newRxDownload.ProgressListener() {
@OverridepublicvoidonProgress(floatprogress, longdownloadLength, longcontentLength) {
pb_1.setProgress((int) (progress * 10000));
}
})
.setSpeedListener(newRxDownload.SpeedListener() {
@OverridepublicvoidonSpeedChange(floatbytePerSecond, StringspeedFormat) {
tv_start.setText("正在下载(" + speedFormat + ")");
}
});
tv_start.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(Viewv) {
mRxDownload.start();
}
});
tv_stop.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(Viewv) {
mRxDownload.stop();
}
});
tv_cancel.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(Viewv) {
mRxDownload.cancel();
}
});用于初始化和设置
RxDownload的设置
指定默认BaseUrl,传入一个合法的就可以了
指定超时时间,建议长一点,如60秒
设置0则取getTimeout(),单位毫秒
设置0则取getTimeout(),单位毫秒
设置0则取getTimeout(),单位毫秒
指定默认的下载文件夹路径
获取保存路径的文件已存在但未保存下载进度时的默认模式
用于保存下载信息,如需断点续传,需要自己保存以下几个必传项
下载文件的链接**(必传项)**
自定义下载文件的保存目录**(断点续传时必传项)**
自定义下载文件的保存文件名,需带后缀名**(断点续传时必传项)**
已下载文件的长度**(断点续传时必传项)**
下载文件的总长度
当前下载状态
正在开始
正在下载
未开始/已停止
下载出错
下载完成
获取保存路径的文件已存在但未保存下载进度时的模式
追加
替换
重命名
创建一个下载对象,参数为url
创建一个下载对象,参数为url/保存目录/文件名
创建一个下载对象,参数为url/保存目录/文件名/已下载长度/总长度
用于新建一个下载任务
设置下载状态监听
正在开始,正在连接服务器
正在下载
已停止,不会删除已下载部分,支持断点续传
已取消,会删除已下载的部分文件,再次开始会重新下载
下载完成
下载出错
下载进度回调(0~1)
下载速度回调,两个值分别为每秒下载比特数和格式化后速度(如:1.2KB/s,3.24MB/s)
开始下载/继续下载
停止下载,不会删除已下载部分,支持断点续传
取消下载,会删除已下载的部分文件,再次开始会重新下载
单位格式化工具
计算速度
格式化速度(如:1.12MB/s,628KB/s)
格式化速度(如:1.12MB/s,628KB/s)
格式化比特值(如:12.1KB,,187.24MB,154GB)
格式化时间单位(如:秒为s,毫秒为ms)