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 = 10
		this.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的數據沒有被完整下載。應該是不會存儲到數據庫的,那么這一部分的數據就要又一次下載,在下載完畢之后,數據拼接起來就是一個完整的文件了。







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM