Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 網絡學習之使用多線程下載,支持斷點續傳

Android 網絡學習之使用多線程下載,支持斷點續傳

編輯:關於Android編程

既然本節是學習如何使用多線程下載,那我們先要明白什麼是多線程下載,在搞明白什麼是多線程下載之前,需要先知道什麼是單線程下載。

\

上圖就是說明了單線程下載的原來,因此單線程下載速度很慢,因為只有一個任務在干活。

\

這樣的話,3個線程下載一個文件,總比1個線程一個文件的速度要快。所以多線程下載數據的速度就快。

既然知道了多線程的下載原理,那我們就分析多個線程是如何下載數據,以及如何保存數據的。

\

知道多線程下載的原理,以及每個線程如何存放數據後,那就開始寫代碼。

1: 當然先要獲取該數據的大小了,這樣才知道給每個線程分配多大的下載量

我在服務器上下載一個exe文件名為:wireshark.exe

\

先從服務器上獲取該文件的大小,並計算每個線程應該下載的大小區間

 

public void downloade(View v)
    {
    	Thread thread = new Thread()
    	{
    		//服務器地址
    		String path = http://192.168.1.123:8080/Wireshark.exe;
    		@Override
    		public void run() {
    			try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setRequestMethod(GET);
					conn.setReadTimeout(5000);
					conn.setReadTimeout(5000);
					
					if(conn.getResponseCode() == 200)
					{
						//獲取數據的總大小
						int length = conn.getContentLength();
						//每個線程的大小
						int size = length / threadCount;
						
						for(int i = 0; i < threadCount; i++)
						{
							int startIndex = i * size;
							int endIndex = (i + 1)*size - 1;
							//最後一個線程的結束地址為文件總大小-1
							if(i == threadCount - 1)
							{
								endIndex = length - 1;
							}
							
							System.out.println(線程 + i + 的下載區間為: + startIndex + --- + endIndex);
						}
						
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
    		}
    	};
    	
    	thread.start();
    }

打印結果為:

 

\

可以看到大小是正確的。總的大小為29849552大小

2: 既然已經給每個線程分好了下載區間,那我們就開始下載

在下載開始時,先要在存儲設備上分配一個個下載文件一樣大小的臨時文件,這樣可以避免下載過程中出現存儲不夠。

 

System.out.println(線程 + i + 的下載區間為: + startIndex + --- + endIndex);
							//開啟threadCount去下載數據
							new downloadThread(startIndex, endIndex, i).start();

class downloadThread extends Thread{
    	int startIndex;//開始位置
    	int endIndex;//結束位置
    	int threadId;//線程Id
    	
    	//構造方法
		public downloadThread(int startIndex, int endIndex, int threadId) {
			super();
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.threadId = threadId;
		}
		
		@Override
		public void run() {
			//這次需要請求要下載的數據了
			URL url;
			try {
				url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod(GET);
				conn.setReadTimeout(5000);
				conn.setReadTimeout(5000);
				//設置本次HTTP請求數據的區間
				conn.setRequestProperty(Range, bytes= + startIndex + - + endIndex);
				//請求部分數據,返回碼為206
				if(conn.getResponseCode() == 206)
				{
					//此時取到的流裡的數據只有上面給定區間的大小
					InputStream is = conn.getInputStream();
					byte[] b = new byte[1024];
					int len = 0;
					int total = 0;
					
					//再次打開臨時文件
					File file = new File(Environment.getExternalStorageDirectory(), filename);
					RandomAccessFile raf = new RandomAccessFile(file, rwd);
					//把文件的寫入位置指定到startindex
					raf.seek(startIndex);
					
					while((len = is.read(b)) != -1)
					{
						raf.write(b, 0, len);
						total += len;
						System.out.println(線程 + threadId + 下載了 + total);
					}
					
					System.out.println(線程 + threadId + ---------------下載完畢-------------------);
					raf.close();
				}
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
    }

從打印中可以看到是可以下載成功的。

 

3: 既然下載東西,對用戶來說就的知道下載的進度。我們使用進度條顯示現在的進度

設置最大進度

 

//獲取數據的總大小
						int length = conn.getContentLength();
						
						//設置進度條的最大值
						pBar.setMax(length);
						
						//每個線程的大小
						int size = length / threadCount;

這是當前的進度

 

 

						raf.write(b, 0, len);
						total += len;
						System.out.println(線程 + threadId + 下載了 + total);
						
						//設置當前進度,是3個線程的總和
						currProgress += len;
						pBar.setProgress(currProgress);

再設置文本顯示,當前比例。要使用消息來更新UI

 

 

	Handler handler = new Handler()
	{
		public void handleMessage(android.os.Message msg) 
		{
			//顯示下載比例,轉為為long型,int的時候有時候不夠大
			tView.setText((long)pBar.getProgress() * 100 / pBar.getMax() + %);
		};
	};

效果圖:

 

\

接下來實現斷點續傳:

 

 

			File bakFile = new File(Environment.getExternalStorageDirectory(), threadId + .txt);
			try {
				//判斷文件是否存在
				if(bakFile.exists())
				{
					FileInputStream fis = new FileInputStream(bakFile);
					BufferedReader bReader = new BufferedReader(new InputStreamReader(fis));
					//從進度臨時文件中讀取出上一次下載的總進度,然後與原本的開始位置相加,得到新的開始位置
					int lastProgress = Integer.parseInt(bReader.readLine());
					startIndex += lastProgress;
					
					//把上次下載的進度顯示至進度條
					currProgress += lastProgress;
					pBar.setProgress(currProgress);
					
					//發送消息,讓主線程刷新文本進度
					handler.sendEmptyMessage(1);
					fis.close();
				}
在下載時候,先需要創建配置文件,防止下載過程中某些原因導致停止下載,當後續接著下載時,還是會用上次下載的地方接著下載

 

 

					while((len = is.read(b)) != -1)
					{
						raf.write(b, 0, len);
						total += len;
						System.out.println(線程 + threadId + 下載了 + total);
						
						//設置當前進度,是3個線程的總和
						currProgress += len;
						pBar.setProgress(currProgress);
						//通過發送消息,更新文本。而進度條不需要通過發消息刷新UI,因為進度條本身就是在別的任務中使用的
						handler.sendEmptyMessage(1);
						
						//將當前的下載進度保存到配置文件中
						RandomAccessFile bakRaFile = new RandomAccessFile(bakFile, rwd);
						bakRaFile.write((total + ).getBytes());
						bakRaFile.close();
					}
可以正常的支持斷點連續下載

 

\

下載的文件可以正常運行,我將下載文件轉為feiq了,因為wireshark有點大

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved