RxJava2.x+ReTrofit2.x多线程下载文件的示例代码
写在前面: 接到公司需求:要做一个apk升级的功能,原理其实很简单,百度也一大堆例子,可大部分都是用框架,要么就是HttpURLConnection,实在是不想这么干。正好看了两天的RxJava2.x+ReTrofit2.x,据说这俩框架是目前最火的异步请求框架了。固本文使用RxJava2.x+ReTrofit2.x实现多线程下载文件的功能。 思路分析: 思路及其简洁明了,主要分为以下四步 1.获取服务器文件大小. 来,接下来是你们最喜欢的撸代码环节 1.首先看引用 compile 'io.reactivex:rxjava:latest.release' compile 'io.reactivex:rxandroid:latest.release' //network - squareup compile 'com.squareup.retrofit2:retrofit:latest.release' compile 'com.squareup.retrofit2:adapter-rxjava:latest.release' compile 'com.squareup.okhttp3:okhttp:latest.release' compile 'com.squareup.okhttp3:logging-interceptor:latest.release' 2.构造一个下载接口DownloadService.class public interface DownloadService { @Streaming @GET //downParam下载参数,传下载区间使用 //url 下载链接 Observable<ResponseBody> download(@Header("RANGE") String downParam,@Url String url); } 3.为了使用方便封装了一个RetrofitHelper.class,主要用于: a)实例化OkHttpClient和Retrofit. public RetrofitHelper(String url,DownloadProgressListener listener) { DownloadProgressInterceptor interceptor = new DownloadProgressInterceptor(listener); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(interceptor) .retryOnConnectionFailure(true) .connectTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS) .build(); retrofit = new Retrofit.Builder() .baseUrl(url) .client(client) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); } b)封装下载方法,本次下载我使用的是三个下载线程,并没有动态分配,各位可以根据自己的需求去动态分配线程个数 public Observable download(@NonNull final long start,@NonNull final long end,@NonNull final String url,final File file,final Subscriber subscriber) { String str = ""; if (end == -1) { str = ""; } else { str = end + ""; } return retrofit.create(DownloadService.class).download("bytes=" + start + "-" + str,url).subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).map(new Func1<ResponseBody,ResponseBody>() { @Override public ResponseBody call(ResponseBody responseBody) { return responseBody; } }).observeOn(Schedulers.computation()).doOnNext(new Action1<ResponseBody>() { @Override public void call(ResponseBody responseBody) { //第一次请求全部文件长度 if (end == -1) { try { RandomAccessFile randomFile = new RandomAccessFile(file,"rw"); randomFile.setLength(responseBody.contentLength()); long one = responseBody.contentLength() / 3; download(0,one,url,file,subscriber).mergeWith(download(one,one * 2,subscriber)).mergeWith(download(one * 2,responseBody.contentLength(),subscriber)).subscribe(subscriber); } catch (IOException e) { e.printStackTrace(); } } else { FileUtils fileUtils = new FileUtils(); fileUtils.writeFile(start,end,responseBody.byteStream(),file); } } }).subscribeOn(AndroidSchedulers.mainThread()); } 4.调用下载 注:调用下载在MainAcitivity中进行,为了直观我们封装了进度拦截器以方便实现进度显示,但是本篇不在叙述进度拦截器的实现过程,如有需要可以留言。 a)实现监听对象 subscriber = new Subscriber() { @Override public void onCompleted() { Log.e("MainActivity","onCompleted下下载完成"); // Toast.makeText(MainActivity.this,"onCompleted下下载完成",Toast.LENGTH_LONG).show(); installAPK("mnt/sdcard/aaaaaaaaa.apk"); } @Override public void onError(Throwable e) { e.printStackTrace(); Log.e("MainActivity","onError: " + e.getMessage()); } @Override public void onNext(Object o) { } }; b)调用封装的RetrofitHelper实现下载 RetrofitHelper RetrofitHelper = new RetrofitHelper("http://gdown.baidu.com/data/wisegame/0904344dee4a2d92/",new DownloadProgressListener() { @Override public void update(long bytesRead,long contentLength,boolean done) { SharedPF.getSharder().setLong("update",bytesRead); pro.setProgress((int) ((double) bytesRead / contentLength * 100)); temp++; if (temp <= 1) { Log.e("MainActivity","update" + bytesRead + ""); } } }); RetrofitHelper.download(0,-1,"QQ_718.apk",new File("mnt/sdcard/","aaaaaaaaa.apk"),subscriber).subscribe(new Subscriber() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Object o) { } }); } 注:最后贴一个apk安装的方法 // 安装APK public void installAPK(String filePath) { Intent intent = new Intent(); intent.setAction("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 广播里面操作需要加上这句,存在于一个独立的栈里 intent.setDataAndType(Uri.fromFile(new File(filePath)),"application/vnd.android.package-archive"); mainActivity.startActivity(intent); } 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |