Android多線程實現文件斷點下載

f663x 10年前發布 | 4K 次閱讀 Java Android

download_main_layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&quot;
    xmlns:tools="http://schemas.android.com/tools&quot;
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

<EditText
    android:id="@+id/down_load_edt"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:hint="請輸入下載文件的網址!" />


<Button
    android:layout_marginTop="20dp"
    android:id="@+id/down_load_btn"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="點擊下載" />


<ProgressBar
    android:id="@+id/down_load_pbar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />


</LinearLayout></pre>


下載入口Activity:

public class MainActivity extends Activity implements OnClickListener {
/下載文件按鈕 */
private Button downLoadBtn;
/下載文件地址 /
private EditText downLoadEdt;
/**下載進度 /
private ProgressBar downLoadPbar;
/定義發送消息的字段*/
private static final int MESSAGE_NUMBER = 1;
/所要下載文件總大小 /
private int fileSize;
/**已下載大小 /
private int downLoadSize;
/所下載文件的保存路徑 */
private String path;
/更新進度條的值 /
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == MESSAGE_NUMBER) {
/**設置進度/
downLoadPbar.setProgress(Double.valueOf(downLoadSize  1.0 / fileSize  100).intValue());
}
}

};

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.download_activity_main); findViews(); setListeners(); initdata(); }

private void findViews() { downLoadEdt=(EditText) findViewById(R.id.down_load_edt); downLoadBtn = (Button) findViewById(R.id.down_load_btn); downLoadPbar = (ProgressBar) findViewById(R.id.down_load_pbar); }

private void setListeners() { downLoadBtn.setOnClickListener(this); }

private void initdata() { downLoadPbar.setVisibility(View.GONE); downLoadPbar.setMax(100); downLoadPbar.setProgress(0); }

@Override public void onClick(View v) { /獲取SDcard */ path = Environment.getExternalStorageDirectory() + "/downloads/"; File file = new File(path); if (!file.exists()) { file.mkdir(); } /下載操作 / new Thread(new DownLoadTask()).start(); /**顯示進度條 / downLoadPbar.setVisibility(View.VISIBLE); }

/子線程,計算下載量,更新UI */ class DownLoadTask implements Runnable { /線程塊大小,每個線程的下載量 / private int blockSize; /** 默認為5個線程 / private int threadNum = 5; /* 下載后的文件名 / private String fileName = "myDownLoad.zip";

@Override public void run() { /數組保存線程對象,便于后面的每個線程下載量計算總和 */ DownLoadThread[] fileDownLoads = new DownLoadThread[threadNum]; / 計算總大小 / URL url; try { url = new URL(downLoadEdt.getText().toString().trim()); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); /**計算下載量 / fileSize = conn.getContentLength(); / 計算每個線程的下載量 */ blockSize = fileSize / threadNum; / 執行下載操作 / for (int i = 0; i < threadNum; i++) { /** 每個線程的開始位置 / int begin = i blockSize; /** 每個線程的結束位置 / int end = (i + 1) * blockSize - 1; DownLoadThread thread = new DownLoadThread(url, begin, end, path + fileName); thread.start(); fileDownLoads[i] = thread; }

/* 更新UI / boolean flag = false; while (!flag) { flag = true; for (int i = 0; i < threadNum; i++) { downLoadSize += fileDownLoads[i].getDownloadsize(); if (!fileDownLoads[i].isFinish()) { flag = false; } } MainActivity.this.handler.sendEmptyMessage(MESSAGE_NUMBER); Thread.sleep(1000); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

下載線程工具類:

public class DownLoadThread extends Thread { /文件年在Url*/ private URL url; /文件下載開始位置/ private int startPostion; /**文件下載結束位置/ private int endPostion; /文件下載當前位置*/ private int currentPostion; /文件名/ private String filename; /**緩沖輸入流/ private BufferedInputStream buffin; /寫入流,支持斷點*/ private RandomAccessFile raf; /緩沖大小/ byte[] buffsize = new byte[1024]; /**已經下載大小/ private int downloadsize; /*下載是否完成/ private boolean isFinish;

public int getDownloadsize() { return downloadsize; } public boolean isFinish() { return isFinish; }

public DownLoadThread(URL url, int begin, int end, String filename) { super(); this.url = url; this.startPostion = begin; this.endPostion = end; this.filename = filename; } @Override public void run() { try { /**

  • 抽象類 URLConnection 是所有類的超類,它代表應用程序和 URL 之間的通信鏈接。此類的實例可用于讀取和寫入此 URL 引用的資源。通常,創建一個到 URL 的連接需要幾個步驟:
  • openConnection() connect()對影響到遠程資源連接的參數進行操作。 與資源交互;查詢頭字段和內容。
  • 通過在 URL 上調用 openConnection 方法創建連接對象。 處理設置參數和一般請求屬性。 使用 connect 方法建立到遠程對象的實際連接。 遠程對象變為可用。遠程對象的頭字段和內容變為可訪問。 / URLConnection conn = url.openConnection(); /**指定下載的范圍/ conn.setRequestProperty("Range", "bytes="+startPostion+"-"+endPostion); /此URL將在一定的上下文環境中被檢驗,是否允許用戶交互,比如彈出一個認證對話框。如果為 false,那么不允許用戶交互。*/ conn.setAllowUserInteraction(true); /做緩沖優化處理/ buffin = new BufferedInputStream(conn.getInputStream()); /**寫入本地文件/ raf = new RandomAccessFile(new File(filename), "rw"); /*移動到新的位置/ raf.seek(startPostion);

while(currentPostion<endPostion){//如果當前下載沒有結束 int size = buffin.read(buffsize, 0, 1024); /已經讀完*/ if(size==-1){ break; } raf.write(buffsize, 0, size); currentPostion+=size; /下載量/ downloadsize+=size; } isFinish = true; /**下載完成就要關閉輸入流與寫入流/ buffin.close(); raf.close();

} catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } super.run(); }

}</pre>

不要忘記在清單文件AndroidManifest.xml中設置相應權限:

 <!-- 網絡訪問權限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- sdcard權限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 本文由用戶 f663x 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!