千家信息网

如何使用Retrofit+RxJava实现带进度条的文件下载

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇文章主要为大家展示了"如何使用Retrofit+RxJava实现带进度条的文件下载",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"如何使用Retrofi
千家信息网最后更新 2025年01月19日如何使用Retrofit+RxJava实现带进度条的文件下载

这篇文章主要为大家展示了"如何使用Retrofit+RxJava实现带进度条的文件下载",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"如何使用Retrofit+RxJava实现带进度条的文件下载"这篇文章吧。

先说一下版本控制吧,通用做法基本上是通过接口获取服务器存储的app版本号,与应用的版本号进行比较,版本较低就去更新,先看一下如何获取应用版本号吧

PackageManager packageManager = mActivity.getPackageManager(); PackageInfo packageInfo = null; try { packageInfo = packageManager.getPackageInfo(mActivity.getPackageName(), 0); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } String versionName = packageInfo.versionName;

可以看到使用的是Context中的getPackageManager方法来获取PackageManager 对象,该对象可用于获取版本的一些信息。

上面的属于附内容,接下来就是关于Retrofit+RxJava实现进度条下载文件的功能,Retrofit本身不提供进度条显示的功能,但Retrofit默认使用Okhttp来进行网络请求,这里就可以自定义拦截器来进行拦截,实现进度。Okhttp的Demo中也为我们提供了一份代码,需要的可以去参考一下Progress.javar,可以看到拦截器的设置:

public class ProgressResponseBody extends ResponseBody { private ResponseBody responseBody; private ProgressListener progressListener; private BufferedSource bufferedSource; public ProgressResponseBody(ResponseBody responseBody,ProgressListener progressListener){ this.responseBody=responseBody; this.progressListener=progressListener; } @Override public MediaType contentType() { return responseBody.contentType(); } @Override public long contentLength() { return responseBody.contentLength(); } @Override public BufferedSource source() { if(bufferedSource==null){ bufferedSource= Okio.buffer(source(responseBody.source())); } return bufferedSource; } private Source source(Source source) { return new ForwardingSource(source) { long totalBytesRead = 0L; @Override public long read(Buffer sink, long byteCount) throws IOException { //当前读取字节数 long bytesRead = super.read(sink, byteCount); //增加当前读取的字节数,如果读取完成了bytesRead会返回-1 totalBytesRead += bytesRead != -1 ? bytesRead : 0; //回调,如果contentLength()不知道长度,会返回-1 progressListener.onProgress(totalBytesRead,responseBody.contentLength(),bytesRead,bytesRead==-1); return bytesRead; } }; }}

ProgressListener 用来监听进度变化,回调到ProgressInterceptor中,ProgressInterceptor是一个自定义的拦截器,可以看一下代码

public class ProgressInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Response response=chain.proceed(chain.request()); return response.newBuilder().body(new ProgressResponseBody(response.body(),progressListener)).build(); } static final ProgressListener progressListener=new ProgressListener() { @Override public void onProgress(long progress, long total, long speed, boolean done) { Log.i("log","progress="+progress+"total="+total); } };}

为了便于获取progress,可以通过OkHttpClient的addNetworkInterceptor方法直接添加一个自定义的拦截器,例如:

//为Okhttp设置拦截器 OkHttpClient client = new OkHttpClient.Builder() .addNetworkInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder() .body(new ProgressResponseBody(originalResponse.body(), progressListener)) .build(); } }) .build(); //进度回调监听 ProgressListener progressListener=new ProgressListener() { @Override public void onProgress(long progress, long total, long speed, boolean done) { Message message=new Message(); message.obj=new AmallLoadBean(progress,total); progressHandler.sendMessage(message); } };

这里通过一个创建一个继承自Handler的ProgressHandler静态内部类用于在主线程中刷新进度,顺带提一下,使用static修饰ProgressHandler是因为静态内部类默认不持有外部类对象的引用,需要注意一下Handler的内存泄漏,使用一下写法:

//处理下载版本进度 public class ProgressHandler extends Handler{ private WeakReference mActivityWeakReference; public ProgressHandler(Activity activity){ mActivityWeakReference=new WeakReference(activity); } @Override public void handleMessage(Message msg) { if(mActivityWeakReference.get()!=null){ AmallLoadBean amallLoadBean= (AmallLoadBean) msg.obj; long progress=amallLoadBean.getProgress(); long total=amallLoadBean.getTotal(); float cp=(float)progress/(float)total; } } }

继续回到下载文件中,我才用的是Retrofit+RxJava的方法来实现,写之前也看了一下别人写的,好像不全,下满也遇到了一些小坑,讲一下吧:

observable.subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .doOnNext(new Action1() { @Override public void call(ResponseBody responseBody) { saveFiles(responseBody); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @Override public void onCompleted() { installApk(); } @Override public void onError(Throwable e) { ToastUtils.getInstance().showToast("请到应用市场下载最新版本"); } @Override public void onNext(ResponseBody responseBody) { } }); }

通过RxJava的doOnNext在subscribe方法之前存储文件,这里需要注意的是doOnNext方法需要在子线程中执行,调用.observeOn(Schedulers.io())方法,然后再切换到主线程,否则文件下载不下来。当文件下载完成时,在onCompleted方法中执行installApk()方法安装app。需要注意的是这里需要做权限的适配,因为我的是自己封装的因为就不拿出来了,挺简单就自己写吧。保存文件的代码给大家放出来了,通俗的语言:

/** * 保存文件 */ public void saveFiles(ResponseBody responseBody){ InputStream inputStream = null; FileOutputStream fileOutputStream = null; byte[] buffer=new byte[2048]; int len; File file=new File(saveFileName); if(!file.exists()){ file.mkdirs(); } try { inputStream=responseBody.byteStream(); fileOutputStream=new FileOutputStream(file); while ((len=inputStream.read(buffer))!=-1){ fileOutputStream.write(buffer,0,len); } inputStream.close(); fileOutputStream.close(); } catch (Exception e) { e.printStackTrace(); } }

在安装文件的时候,需要注意7.0以后的适配,代码看看就好,和拍照适配的原理一直,都是Android对私密性文件的权限问题

/** * 安装apk * */ private void installApk() { File apkfile = new File(saveFileName); if (!apkfile.exists()) { return; } //判断版本号 if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){ Uri apkUri = FileProvider.getUriForFile(activity, "******.fileprovider", apkfile); Intent install = new Intent(Intent.ACTION_VIEW); install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //添加这一句表示对目标应用临时授权该Uri所代表的文件 install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); install.setDataAndType(apkUri, "application/vnd.android.package-archive"); activity.startActivity(install); }else{ Intent i = new Intent(Intent.ACTION_VIEW); i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive"); activity.startActivity(i); } }

以上是"如何使用Retrofit+RxJava实现带进度条的文件下载"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

文件 进度 版本 方法 文件下载 拦截器 代码 内容 应用 对象 篇文章 线程 适配 功能 字节 权限 静态 存储 学习 帮助 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 车机系统软件开发 达梦数据库中删除字段类型的语句 花生壳内网穿透数据库 自动生成数据库的字段和表 叙述软件开发周期 山西专业软件开发厂家现货 东南网络安全毕业待遇 服务器运维管理公司 棋牌游戏软件开发投资多少 数据库可视化操作工具 普法网络安全教育平台 学生正确认识网络安全的重要性 奥维地图企业服务器帮助手册 网络安全知识答题规则 a330更新导航数据库 通常主机游戏用什么软件开发 阿里云服务器登录名 网络安全和互联网应用开发 怎么查服务器开放的主要服务 三级分销软件开发原理 数据库选型图解 打印机服务器一直不关机 河南时代网络技术分类代理商 叙述软件开发周期 网络安全法宣传讲座讲稿 潍坊众信网络技术有限公司 5g网络技术已经非常成熟 网络安全技术专业有前途吗 河南省互联网科技学校 网上订购机票数据库设计
0