編輯:關於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);
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有點大
國產手機的集體高潮,卻使消費者變的“煩惱了”,因為消費者在購買手機時變得越來越猶豫糾結。以2499元這個價位的手機來說,單國產手機就
先給大家展示下效果展示圖:1 簡介如果想在Activity中得到新打開Activity 關閉後返回的數據,需要使用系統提供的startActivityForResult(
好不容易周末有空,作為一個零基礎非計算機專業剛培訓出來7個月的小白,對付博大精深的Android源碼真的是心有余而力不足,但是東西還是要學滴,這不!找到Hongyang大
首先描述下我們想要實現的內容,我們希望在一個應用中通過點擊按鈕,去操作另一個進程中應用的音樂播放功能。如圖,我們點擊“播放”時,系統就會去遠程調用我們提供的一個servi