日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 断点续传实现原理

發布時間:2024/9/30 Android 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 断点续传实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/120956134
本文出自【趙彥軍的博客】

文章目錄

  • 下載原理
  • 斷點續傳原理
    • 1、java.io.RandomAccessFile
    • 2、請求響應碼及Header
    • 3、處理請求資源發生改變的問題
    • 4、文件可復用判斷

下載原理

在介紹斷點續傳之前,我們先說說下載的原理。代碼示例用 OkHttp 作為示例。

下載核心思路是把 responseBody 寫入文件,核心代碼如下:

但是這種做法有個明顯的問題,假如手機在下載文件的時候下載了80%,某些原因斷網了,如果不支持斷點續傳,那就只有被迫重頭開始下載。但是如果有斷點續傳的加持,就只需要下載最后 20% 的資源,避免重新下載。

斷點續傳原理

1、java.io.RandomAccessFile

斷點續傳/下載需要使用到 java.io.RandomAccessFile 類,RandomAccessFile 的實例支持讀取和寫入隨機訪問文件,它也可以 seek(long pos) 設置從此文件的開頭開始測量的文件指針偏移量,在該位置進行下一次讀取或寫入操作。簡單點說就是可以通過 seek(long pos)方法跳過pos字節開始寫入字節。

如何創建一個 RandomAccessFile ?

//rw:支持可讀可寫 val file = RandomAccessFile(file, "rw")

假如我有一段文本要寫入文件,但是需要從文件的第100個字節開始寫,那么需要調用 seek(long pos ) 方法跳過前 100 個字節, 具體實現如下:

val file = RandomAccessFile(file, "rw") file.seek(100) file.writeBytes(.....)

所以,我們可以把 responseBody 寫入文件的實現改成如下實現:

2、請求響應碼及Header

正常情況下,我們下載一個文件,響應碼是 200

responseBody 返回的是整個文件的內容。如何才能返回部分內容?
在實現分塊請求之前,首先要判斷服務器是否支持分塊返回,標志是 Access-Ranges ,值為 bytes 就代表服務器支持分塊返回,也就是支持斷點續傳。

所以,我們可以封裝一個方法,來判斷服務是否支持斷點續傳

在確定了服務器支持分塊傳輸后,我們就可以在請求資源的時候,添加 header 請求 Range 字段,來指定請求實體的范圍。它的范圍取值是在 0-Content-Length 之間,使用 - 分割。

例如已經下載了 1000 bytes 的資源內容,想接著繼續下載之后的資源內容,只要在 HTTP 請求頭部,增加 Range:bytes=1000- 就可以了。

Range 還有幾種不同的方式來限定范圍,可以根據需要靈活定制:

  • 500-1000:指定開始和結束的范圍。
  • 500- :指定開始區間,一直傳遞到結束。這個就比較適用于斷點續傳、或者在線播放等等。
  • -500:無開始區間,只意思是需要最后 500 bytes 的內容實體。
  • 100-300,1000-3000:指定多個范圍,這種方式使用的場景很少,了解一下就好了。

具體舉例如下:

通過抓包我們發現,添加了 Range 后,請求響應碼變成了 206


并且添加 Range 后,響應的 responseBody 就不再是整個文件的內容了,而是一個片段,我們只需要把這個片段的數據直接寫入文件就可以。

注意事項,如何計算 Range 請求頭的開始值,一般取用緩存文件的長度值,如下

val start = targetFile.length()

3、處理請求資源發生改變的問題

在現實的場景中,服務器中的文件是會有發生變化的情況的,那么我們發起續傳的請求肯定是失敗的

那么為了處理這種服務器文件資源發生改變的問題,在 RFC2616 中定義了 Last-Modified和 Etag 來判斷續傳文件資源是否發生改變。

  • Last-Modified:記錄 Http 頁面最后修改時間的 Http 頭部參數,Last-Modified 是由服務端發送給客戶端的
  • Etag:作為文件的唯一標志,這個標志可以是文件的 hash 值或者是一個版本

我們封裝一個方法用來獲取這兩個值

if-Range:用于判斷實體是否發生改變,如果實體未改變,服務器發送客戶端丟失的部分,否則發送整個實體。一般格式:

If-Range: Etag | HTTP-Date

If-Range 可以使用 Etag 或者 Last-Modified 返回的值。當沒有 ETage 卻有 Last-modified 時,可以把 Last-modified 作為 If-Range 字段的值。實現舉例如下:

關于 Etag 、Last-Modified 注意事項:

  • 當第一次請求資源的時候,獲取 Etag/Last-Modified 值,并且保存到本地
  • 當下一次需要斷點續傳的時候,把 Etag/Last-Modified 值取出,添加到請求頭 If-Range 字段

4、文件可復用判斷

在文件下載完成后,如果又發起了一次下載請求,那么此時不應該重復下載的。需要做可復用判斷,思路如下

  • 1、獲取目前已下載文件的大小
  • 2、獲取文件url 獲取服務器文件大小
  • 3、如果已下載大小等于服務器文件大小,則復用已下載的文件

舉例如下:

//獲取已下載文件長度 val downloadLength = targetFile.length() //獲取服務器文件長度 val contentLength = responseBody.contentLength() //兩者長度對比 if(downloadLength == contentLength){//復用已下載文件,不再重復下載 }

總結

以上是生活随笔為你收集整理的Android 断点续传实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。