標籤:android 資料存放區 網路 線程池
1、多線程介紹
用過迅雷的同學都知道,迅雷有個功能叫做多線程,還有一個叫離線下載,我們這裡重點介紹一下多線程下載。多線程,顧名思義就是很多歌線程同時在運行,為什麼要提出多線程這個概念呢?因為有時候一個線程下載太慢了。舉個例子,比如小時候常做的數學題,一個人挖溝需要15天,那麼兩個人對著挖呢?
當然數學題上面兩個人的效率是不一樣的,我們這裡把這個問題簡化了一下,只是想大家明白,什麼是多線程,為什麼有多線程。
在多線程上出現過一個問題,為什麼有要提出多線程?其實提出多線程是為了充分利用CPU的硬體資源,解決應用程式等待的問題。多線程是為了同步完成多項任務,不是為了提高運行效率,而是為了提高資源使用效率來提高系統的效率。線程是在同一時間需要完成多項任務的時候實現的。
2、思路
(1)擷取網路連接
(2)初始化多線程下載資訊,開始下載
(3)開闢硬碟空間,用於存放資料資源
(4)把從網路擷取的資料放入申請的空間中
(5)下載完畢,關閉資源連結
給出一個下載400M電影的,如下所示:
RandomAccessFile支援隨機的訪問
HTTP的Range頭欄位指定每個線程從檔案的什麼位置開始下載。
3、代碼解析
3.1 設定需要下載檔案的資訊
RandomAccessFile randOut = new RandomAccessFile(this.saveFile, "rwd");if(this.fileSize>0){ randOut.setLength(this.fileSize);//設定檔案的大小}randOut.close();//關閉該檔案,使設定生效
3.2 設定下載連結,並且開始劃分下載部分
URL url = new URL(this.downloadUrl);if(this.data.size() != this.threads.length){//如果原先未曾下載或者原先的下載線程數與現在的線程數不一致this.data.clear();//將資料置空for (int i = 0; i < this.threads.length; i++) {//遍曆線程池this.data.put(i+1, 0);//初始化每條線程已經下載的資料長度為0}this.downloadedSize = 0;//設定已經下載的長度為0}
3.3 開始下載檔案
for (int i = 0; i < this.threads.length; i++) {//通過特定的線程ID擷取該線程已經下載的資料長度int downloadedLength = this.data.get(i+1);//判斷線程是否已經完成下載,否則繼續下載if(downloadedLength < this.block && this.downloadedSize < this.fileSize){//初始化特定id的線程this.threads[i] = new DownloadThread(this, url, this.saveFile, this.block, this.data.get(i+1), i+1);//設定線程的優先順序,Thread.NORM_PRIORITY = 5 Thread.MIN_PRIORITY = 1 Thread.MAX_PRIORITY = 10this.threads[i].setPriority(7);//啟動線程this.threads[i].start();}else{this.threads[i] = null;//表明線上程已經完成下載任務}}
3.4 監聽檔案是否下載完成以及完成之後的操作
fileService.delete(this.downloadUrl);//如果存在下載記錄,刪除它們,然後重新添加fileService.save(this.downloadUrl, this.data);//把已經下載的即時資料寫入資料庫
boolean notFinished = true;//下載未完成// 迴圈判斷所有線程是否完成下載while (notFinished) {notFinished = false;//假定全部線程下載完成for (int i = 0; i < this.threads.length; i++){if (this.threads[i] != null && !this.threads[i].isFinished()) {//如果發現線程未完成下載notFinished = true;//設定標誌為下載沒有完成//如果下載失敗,再重新在已經下載的資料長度的基礎上下載if(this.threads[i].getDownloadedLength() == -1){//重新開闢下載線程,代碼與上面一致}}}if(listener!=null){listener.onDownloadSize(this.downloadedSize);}//通知目前已經下載完成的資料長度}//下載完成刪除記錄if(downloadedSize == this.fileSize){fileService.delete(this.downloadUrl);}
4、斷點續傳
斷點續傳是說在下載的時候,我們因為某些原因,導致了下載的暫停,比如在電腦上,我們的電腦突然斷電了,手機上的網路中斷了,都會導致當前的下載任務終止,那麼當我們再次回來的時候,程式應該是可以繼續下載的,不然前面下載的資源就都浪費了。
根據上面的描述,我們應該可以知道,實現斷點續傳,關鍵是實現下載的資料存放區在資料庫中,等到之後我們程式再次進入的時候,會到資料庫中去查詢一下資料,然後接著繼續下載。而儲存資料到資料庫並不是太複雜,難的是如何識別程式的哪些資料被下載了,哪些資料是沒有下載的,這裡,我們在下載的時候使用了下載的線程id做識別。
如果該線程id的資料沒有被完整下載,應該是不會儲存到資料庫的,那麼這一部分的資料就要重新下載,在下載完成之後,資料拼接起來就是一個完整的檔案了。
Android多線程下載大檔案解析