最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Retrofit+RxJava實現(xiàn)帶進度條的文件下載

 更新時間:2019年06月22日 16:52:59   作者:yw_5_24  
這篇文章主要為大家詳細介紹了Retrofit+RxJava實現(xiàn)帶進度條的文件下載,具有一定的參考價值,感興趣的小伙伴們可以參考一下

項目中需要使用到更新版本,因此研究了一下Retrofit的下載文件,和進度條效果,其間也遇到了一些坑,寫出來加深一下記憶,也為別的同學提供一下思路。

先說一下版本控制吧,通用做法基本上是通過接口獲取服務(wù)器存儲的app版本號,與應(yīng)用的版本號進行比較,版本較低就去更新,先看一下如何獲取應(yīng)用版本號吧

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 對象,該對象可用于獲取版本的一些信息。

上面的屬于附內(nèi)容,接下來就是關(guān)于Retrofit+RxJava實現(xiàn)進度條下載文件的功能,Retrofit本身不提供進度條顯示的功能,但Retrofit默認使用Okhttp來進行網(wǎng)絡(luò)請求,這里就可以自定義攔截器來進行攔截,實現(xiàn)進度。Okhttp的Demo中也為我們提供了一份代碼,需要的可以去參考一下Progress.javar,可以看到攔截器的設(shè)置:

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 {
 //當前讀取字節(jié)數(shù)
 long bytesRead = super.read(sink, byteCount);
 //增加當前讀取的字節(jié)數(shù),如果讀取完成了bytesRead會返回-1
 totalBytesRead += bytesRead != -1 ? bytesRead : 0;
 //回調(diào),如果contentLength()不知道長度,會返回-1

 progressListener.onProgress(totalBytesRead,responseBody.contentLength(),bytesRead,bytesRead==-1);
 return bytesRead;
 }
 };
 }
}

ProgressListener 用來監(jiān)聽進度變化,回調(diào)到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設(shè)置攔截器
 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();

 //進度回調(diào)監(jiān)聽
 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);
 }
 };

這里通過一個創(chuàng)建一個繼承自Handler的ProgressHandler靜態(tài)內(nèi)部類用于在主線程中刷新進度,順帶提一下,使用static修飾ProgressHandler是因為靜態(tài)內(nèi)部類默認不持有外部類對象的引用,需要注意一下Handler的內(nèi)存泄漏,使用一下寫法:

//處理下載版本進度
 public class ProgressHandler extends Handler{

 private WeakReference<Activity> mActivityWeakReference;
 public ProgressHandler(Activity activity){

 mActivityWeakReference=new WeakReference<Activity>(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;

 }
 }
 }

繼續(xù)回到下載文件中,我才用的是Retrofit+RxJava的方法來實現(xiàn),寫之前也看了一下別人寫的,好像不全,下滿也遇到了一些小坑,講一下吧:

observable.subscribeOn(Schedulers.io())
 .observeOn(Schedulers.io())
 .doOnNext(new Action1<ResponseBody>() {
  @Override
  public void call(ResponseBody responseBody) {

  saveFiles(responseBody);
  }
 })
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(new Observer<ResponseBody>() {
  @Override
  public void onCompleted() {
  installApk();

  }

  @Override
  public void onError(Throwable e) {

  ToastUtils.getInstance().showToast("請到應(yīng)用市場下載最新版本");
  }

  @Override
  public void onNext(ResponseBody responseBody) {

  }
 });
 }

通過RxJava的doOnNext在subscribe方法之前存儲文件,這里需要注意的是doOnNext方法需要在子線程中執(zhí)行,調(diào)用.observeOn(Schedulers.io())方法,然后再切換到主線程,否則文件下載不下來。當文件下載完成時,在onCompleted方法中執(zhí)行installApk()方法安裝app。需要注意的是這里需要做權(quán)限的適配,因為我的是自己封裝的因為就不拿出來了,挺簡單就自己寫吧。保存文件的代碼給大家放出來了,通俗的語言:

/**
 * 保存文件
 */
 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對私密性文件的權(quán)限問題

 /**
 * 安裝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);
 //添加這一句表示對目標應(yīng)用臨時授權(quán)該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);
 }

 }

基本上就這些,后續(xù)我會在此篇文章上繼續(xù)補充。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • java中全排列的生成算法匯總

    java中全排列的生成算法匯總

    本文給大家匯總介紹了常見的6種全排列的生成算法,包括字典序法、遞增進位數(shù)制法、遞減進位數(shù)制法、鄰位交換法、遞歸類算法、元素增值法,有需要的小伙伴可以參考下
    2015-07-07
  • Spring Boot企業(yè)常用的starter示例詳解

    Spring Boot企業(yè)常用的starter示例詳解

    這篇文章主要給大家介紹了關(guān)于Spring Boot企業(yè)常用starter的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring Boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-12-12
  • 23種設(shè)計模式(17)java命令模式

    23種設(shè)計模式(17)java命令模式

    這篇文章主要為大家詳細介紹了23種設(shè)計模式之java命令模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • springboot無法從靜態(tài)上下文中引用非靜態(tài)變量的解決方法

    springboot無法從靜態(tài)上下文中引用非靜態(tài)變量的解決方法

    這篇文章主要介紹了springboot無法從靜態(tài)上下文中引用非靜態(tài)變量的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-06-06
  • Spring Boot管理用戶數(shù)據(jù)的操作步驟

    Spring Boot管理用戶數(shù)據(jù)的操作步驟

    SpringBoot結(jié)合Thymeleaf模板引擎,可以快速搭建Web應(yīng)用,介紹了使用SpringBoot處理JSON數(shù)據(jù)的基本過程,包括創(chuàng)建實體類、視圖頁面和控制器,通過這些步驟,即可完成基于SpringBoot和Thymeleaf的簡單Web開發(fā),感興趣的朋友跟隨小編一起看看吧
    2024-09-09
  • 基于java枚舉類綜合應(yīng)用的說明

    基于java枚舉類綜合應(yīng)用的說明

    一個枚舉類,可以看成包括它的一些子類(枚舉)的一個類,而且枚舉類的構(gòu)造方法只能是私有的
    2013-05-05
  • Activiti如何啟動流程并使流程前進

    Activiti如何啟動流程并使流程前進

    這篇文章主要介紹了Activiti如何啟動流程并使流程前進,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • java隨機字符串生成示例

    java隨機字符串生成示例

    這篇文章主要介紹了java隨機字符串生成示例,這個字符隨機生成類可以生成多種組合的字符串,比如大+小字符+數(shù)字+符號,需要的朋友可以參考下
    2014-03-03
  • 詳解spring中的Aware接口功能

    詳解spring中的Aware接口功能

    Spring的依賴注入的最大亮點是所有的Bean對Spring容器的存在是沒有意識的,我們可以將Spring容器換成其他的容器,Spring容器中的Bean的耦合度因此也是極低的,本文重點給大家介紹spring中的Aware接口,感興趣的朋友一起看看吧
    2022-02-02
  • 關(guān)于springboot-starter-undertow和tomcat的區(qū)別說明

    關(guān)于springboot-starter-undertow和tomcat的區(qū)別說明

    這篇文章主要介紹了關(guān)于springboot-starter-undertow和tomcat的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論

祁连县| 调兵山市| 万宁市| 上林县| 新宁县| 成安县| 安西县| 文昌市| 夏河县| 四子王旗| 乃东县| 汨罗市| 盐城市| 东源县| 阿瓦提县| 南安市| 城口县| 黔东| 辽宁省| 白朗县| 青铜峡市| 东丰县| 莒南县| 安阳县| 寻乌县| 浦江县| 安庆市| 博兴县| 沂水县| 伊春市| 临夏市| 靖西县| 德庆县| 阿拉善右旗| 高雄县| 类乌齐县| 康保县| 丽江市| 鹿邑县| 昌吉市| 台州市|