使用OKHttp3实现下载(断点续传、显示进度)
2019獨角獸企業重金招聘Python工程師標準>>>
OKHttp3 是如今非常流行的?Android?網絡請求框架,那么如何利用 Android 實現斷點續傳呢,今天寫了個 Demo 嘗試了一下。
我們會用到 OKHttp3 來做網絡請求,使用 RxJava 來實現線程的切換,并且開啟 Java8 來啟用 Lambda 表達式,畢竟 RxJava 實現線程切換非常方便,而且數據流的形式也非常舒服,同時 Lambda 和 RxJava 配合食用味道更佳。
打開我們的 app Module 下的 build.gradle,代碼如下:
OKHttp 和 RxJava,RxAndroid 使用的都是最新的版本,并且配置開啟了 Java8.
?
布局文件
接著開始書寫布局文件:
其他都差不多,大概是這個樣子的:
3個ProgressBar就是為了顯示進度的,每個 ProgressBar 對應 2個Button,一個是開始下載,一個是暫停(取消)下載,這里需要說明的是,對下載來說暫停和取消沒有什么區別,除非當取消的時候,會順帶把臨時文件都刪除了,在本例里是不區分他倆的.
?
Application
我們這里需要用到一些文件路徑,有一個 全局Context 會比較方便, 而 Application 也是 Context 的子類,使用它的是最方便的,所以我們寫一個類來繼承:
可以看到,我們就是要獲得一個全局的Context對象的
我們在 AndroidManifest 中注冊一下我們的 Application,同時再把我們所需要的權限給上,我們只需要一個網絡權限:
?
DownloadManager
接下來是核心代碼了,就是我們的 DownloadManager,先上代碼:
代碼稍微有點長,關鍵部位我都加了注釋了,我們挑關鍵地方看看
首先我們這個類是單例類,我們下載只需要一個 OKHttpClient 就足夠了,所以我們讓構造方法私有,而單例類的獲取實例方法就是這個 getInstance(); 當然大家用別的方式實現單例也可以的,然后我們在構造方法里初始化我們的 HttpClient,并且初始化一個 HashMap,用來放所有的網絡請求的,這樣當我們取消下載的時候,就可以找到url對應的網絡請求然后把它取消掉就可以了
接下來就是核心的 download 方法了,首先是參數,第一個參數url不用多說,就是請求的網址,第二個參數是一個Observer對象,因為我們使用的是 RxJava,并且沒有特別多復雜的方法,所以就沒單獨寫接口,而是謝了一個 Observer對象 來作為回調,接下來是 DownLoadObserver的代碼:
在 RxJava2 中這個 Observer 有點變化,當注冊觀察者的時候,會調用 onSubscribe方法,而該方法參數就是用來取消注冊的,這樣的改動可以更靈活的有監聽者來取消監聽了,我們的進度信息會一直的傳送的 onNext方法 里,這里將下載所需要的內容封了一個類叫 DownloadInfo:
這個類就是一些基本信息,total 就是需要下載的文件的總大小,而 progress 就是當前下載的進度了,這樣就可以計算出下載的進度信息了
接著看 DownloadManager 的 download 方法,首先通過 url 生成一個 Observable對象,然后通過 filter 操作符過濾一下,如果當前正在下載這個url對應的內容,那么就不下載它。
接下來調用 createDownInfo 重新生成 Observable對象,這里應該用map也是可以的,createDownInfo 這個方法里會調用 getContentLength 來獲取服務器上的文件大小,可以看一下這個方法的代碼:
可以看到,其實就是在通過 OK 進行了一次網絡請求,并且從返回的頭信息里拿到文件的大小信息,一般這個信息都是可以拿到的,除非下載網址不是直接指向資源文件的,而是自己手寫的 Servlet,那就得跟后臺人員溝通好了.注意,這次網絡請求并沒有真正的去下載文件,而是請求個大小就結束了,具體原因會在后面真正請求數據的時候解釋
接著 download方法,獲取完文件大小后,就可以去硬盤里找文件了,這里調用了 getRealFileName 方法:
這個方法就是看本地是否有已經下載過的文件,如果有,再判斷一次本地文件的大小和服務器上數據的大小,如果是一樣的,證明之前下載全了,就再成一個帶(1)這樣的文件,而如果本地文件大小比服務器上的小的話,那么證明之前下載了一半斷掉了,那么就把進度信息保存上,并把文件名也存上,看完了再回到 download 方法
之后就開始真正的網絡請求了,這里寫了一個內部類來實現 ObservableOnSubscribe接口,這個接口也是 RxJava2 的,東西和之前一樣,好像只改了名字,看一下代碼:
主要看 subscribe 方法。首先拿到 url,當前進度信息和文件的總大小,然后開始網絡請求,注意這次網絡請求的時候需要添加一條頭信息:
.addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength)這條頭信息的意思是下載的范圍是多少,downloadLength 是從哪開始下載,contentLength 是下載到哪,當要斷點續傳的話必須添加這個頭,讓輸入流跳過多少字節的形式是不行的,所以我們要想能成功的添加這條信息那么就必須對這個url請求2次,一次拿到總長度,來方便判斷本地是否有下載一半的數據,第二次才開始真正的讀流進行網絡請求。
我還想了一種思路,當文件沒有下載完成的時候添加一個自定義的后綴,當下載完成再把這個后綴取消了,應該就不需要請求兩次了.
接下來就是正常的網絡請求,向本地寫文件了,而寫文件到本地這,網上大多用的是 RandomAccessFile 這個類,但是如果不涉及到多個部分拼接的話是沒必要的,直接使用輸出流就好了,在輸出流的構造方法上添加一個 true 的參數,代表是在原文件的后面添加數據即可,而在循環里,不斷的調用 onNext 方法發送進度信息,當寫完了之后別忘了關流,同時把call對象從 hashMap 中移除了.這里寫了一個 IOUtil 來關流:
其實就是挨一個判斷是否為空,并關閉罷了
這樣download方法就完成了,剩下的就是切換線程,注冊觀察者了
?
MainActivity
最后是activity的代碼:
Activity里沒什么了,就是注冊監聽,開始下載,取消下載這些了,下面我們來看看效果吧:
可以看到 多個下載,斷點續傳什么的都已經成功了,最后我的文件網址是我自己的局域網,大家寫的時候別忘了換了..
代碼地址:
http://download.csdn.net/detail/cfy137000/9746583
轉載于:https://my.oschina.net/JiangTun/blog/911439
總結
以上是生活随笔為你收集整理的使用OKHttp3实现下载(断点续传、显示进度)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IdentityServer4 实现 O
- 下一篇: 《JAVA与模式》之单例模式