android多執行緒斷點下載
阿新 • • 發佈:2018-11-06
多執行緒斷電xia下載,通過設定執行緒的數量,動態獲取下載檔案執行緒的個數,這是本人用於練習所寫demo,註釋很詳細,用於初學者參考使用。
MainActivity.java頁面
package com.dahui.download; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.os.Environment; import android.app.Activity; import android.view.View; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ProgressBar; public class MainActivity extends Activity { private EditText et_path; private EditText et_threadCount; private LinearLayout ll_pb_layout; private String path; private static int runningThread; //代表當前正在執行的執行緒 private int threadCount; private List<ProgressBar> pbList;//用來存進度條的引用 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_path = (EditText) findViewById(R.id.et_path); et_threadCount = (EditText) findViewById(R.id.et_threadCount); ll_pb_layout = (LinearLayout) findViewById(R.id.ll_pb); pbList = new ArrayList<ProgressBar>(); } //點選下載按鈕 public void click(View v){ path = et_path.getText().toString().trim(); //[3]獲取執行緒數量 String threadCountt = et_threadCount.getText().toString().trim(); //[3.1]先移除之前新增的進度條 ll_pb_layout.removeAllViews(); threadCount = Integer.parseInt(threadCountt); pbList.clear();//每次點選清空集合 for (int i = 0; i < threadCount; i++) { //[3.1]把定義的item佈局轉換成view物件 ProgressBar pbView = (ProgressBar) View.inflate(getApplicationContext(), R.layout.item, null); //[3.2]把pbView新增到集合中 pbList.add(pbView); //[4]動態新增進度條 ll_pb_layout.addView(pbView); } //[5]開始移植 聯網 new Thread(){public void run() { //【1】★★★★★★獲取伺服器檔案大小 要計算每個執行緒開始位置和結束位置 try { //String path = "http://192.168.231.2:8080/new1.xml"; URL url = new URL(path); //[2.3]拿到HttpURLConnection物件 用於傳送或接受資料 HttpURLConnection coon = (HttpURLConnection) url.openConnection(); //[2.4]設定傳送get請求 coon.setRequestMethod("GET");//get大寫 預設就是get //請求超時時間 coon.setConnectTimeout(5000); //[2.6]獲取伺服器返回的狀態碼 int code = coon.getResponseCode(); //[2.7]如果code==200 說明請求成功 if (code == 200) { int length = coon.getContentLength(); runningThread = threadCount; //把執行緒的數量賦值給正在執行的執行緒 System.out.println("length"+length); //【2】★★★★★★建立一個大小和伺服器一模一樣的檔案 目的是把空間提前申請出來 RandomAccessFile rafAceAccessFile = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path), "rw"); rafAceAccessFile.setLength(length); //算出每個執行緒下載的大小 int blockSize = length / threadCount; //【3】★★★★★★計算每個執行緒開始位置和結束位置 for (int i = 0; i < threadCount; i++) { int startIndex = i*blockSize; //執行緒開始位置 int endIndex = (i+1)*blockSize - 1; if (i == threadCount -1) { endIndex = length - 1; } System.out.println("執行緒Id:"+i +"理論下載位置"+":"+startIndex+"-----"+endIndex); //【4】★★★★★★開啟執行緒去伺服器下載檔案 DownLoadThread downLoadThread = new DownLoadThread(startIndex, endIndex, i); downLoadThread.start(); } } } catch (Exception e) { e.printStackTrace(); } };}.start(); } public String getFilename(String path){ int start = path.lastIndexOf("/")+1; return path.substring(start); } private class DownLoadThread extends Thread{ //通過構造方法把每個執行緒下載的開始位置和結束位置傳遞出來 private int startIndex; private int endIndex; private int threadId; private int PbMaxSize; //代表當前執行緒下載的最大值 //如果中斷過 則獲取上次下載位置 private int pblastposition; public DownLoadThread(int startIndex,int endIndex,int threadId){ this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; } @Override public void run() { //實現去伺服器下載檔案的邏輯 try { //[0]計算當前進度條的最大值 PbMaxSize = endIndex-startIndex; URL url = new URL(path); //[2.3]拿到HttpURLConnection物件 用於傳送或接受資料 HttpURLConnection coon = (HttpURLConnection) url .openConnection(); //[2.4]設定傳送get請求 coon.setRequestMethod("GET");//get大寫 預設就是get //請求超時時間 coon.setConnectTimeout(5000); //★★★★★★★如果中間斷過,繼續上次的位置下載 從檔案中讀取上次下載的位置 File file = new File(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path)+threadId+".txt"); if (file.exists()&&file.length()>0) { FileInputStream fis = new FileInputStream(file); BufferedReader buff = new BufferedReader(new InputStreamReader(fis)); String lastPositionn = buff.readLine();//讀取出來的內容就是上一次下載的位置 int lastPosition = Integer.parseInt(lastPositionn); //★★給我們定義的進度條賦值 pblastposition = lastPosition - startIndex; //☆☆☆☆☆☆要改變一下startIndex位置 startIndex = lastPosition; System.out.println("執行緒Id:"+threadId +"真實下載位置"+":"+startIndex+"-----"+endIndex); fis.close(); } //設定請求頭Range (告訴伺服器每個執行緒的開始下載和結束位置) coon.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); //[2.6]獲取伺服器返回的狀態碼 int code = coon.getResponseCode(); //[2.7]如果code==200 說明請求成功 206代表請求部分資源成功 if (code == 206) { //建立隨機讀寫檔案物件 RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path), "rw"); //每個執行緒從自己的位置開始寫 raf.seek(startIndex); //[2.8]獲取伺服器返回的資料 以流的形式返回(要把流轉換成字串,此操作比較常見,所以把它做成工具類) InputStream in = coon.getInputStream();//存的是UCBrowser.exe //9把資料寫到檔案中 int len= -1; byte[] buffer = new byte[1024*1024]; int total = 0;//代表當前執行緒下載的大小 while ((len = in.read(buffer))!= -1) { raf.write(buffer,0,len); total+=len; //10.實現斷點續傳 記錄當前下載的位置 int currentThreadPosition = startIndex+total;//把這個位置存起來 //11.用來存當前執行緒下載的位置 RandomAccessFile raff = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path)+threadId+".txt", "rwd"); raff.write(String.valueOf(currentThreadPosition).getBytes()); raff.close(); //設定進度條的最大值和最小值 pbList.get(threadId).setMax(PbMaxSize);//設定進度條最大值 pbList.get(threadId).setProgress(pblastposition+total);//設定進度條當前進度 } raf.close(); //關閉流 釋放資源 System.out.println("執行緒id:"+threadId+"----下載完畢!"); //下載完畢刪除斷點儲存的.txt檔案 synchronized (this) { runningThread--; if(runningThread == 0){ //說明所有執行緒執行完畢 for (int i = 0; i < threadCount; i++) { File delteFile = new File(Environment.getExternalStorageDirectory().getPath()+"/"+getFilename(path)+i+".txt"); delteFile.delete(); } } } } } catch (Exception e) { e.printStackTrace(); } } } }
佈局頁面:activity_main.xml頁面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <EditText android:id="@+id/et_path" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="http://192.168.231.2:8080/UCBrowser.exe" android:hint="請輸入下載的路徑" /> <EditText android:id="@+id/et_threadCount" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="請輸入執行緒的數量" /> <Button android:onClick="click" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下載" /> <LinearLayout android:id="@+id/ll_pb" android:background="#080E12" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > </LinearLayout> </LinearLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?> <ProgressBar xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/progressBar1" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="wrap_content" />
結果截圖:
資源原始碼包下載地址:https://download.csdn.net/download/qq_38993002/10759021