Android多線程檔案下載器

來源:互聯網
上載者:User

標籤:android基礎   線程   


本應用實現的是輸入檔案的網路的地址,點擊按鈕開始下載,下載過程中有進度條和後面的文本提示進度,

下載過程中按鈕不可點擊,防止重複的下載,下載完畢後會進行Toast的提示顯示,

並且回複按鈕的可點擊性,進度條也會清空,當然如果下載中途結束應用進程就會進行進度的儲存,

下次下載同樣的檔案時就會從進度記錄進行下載,節省流量和時間

應用需要的應用許可權:

訪問網路許可權

  <uses-permission android:name="android.permission.INTERNET"/>

外部儲存的寫入許可權

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

布局檔案代碼

<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:ems="10"        android:hint="請輸入下載檔案的地址"        android:singleLine="true"        android:text="http://172.22.64.193:8080/test.exe" >    </EditText>    <TableLayout        android:layout_width="match_parent"        android:layout_height="wrap_content" >        <TableRow            android:layout_width="match_parent"            android:layout_height="wrap_content" >            <ProgressBar                android:id="@+id/pb"                style="?android:attr/progressBarStyleHorizontal"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_weight="8" />            <TextView                android:id="@+id/tv_progressNumber"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_weight="2"                android:gravity="center"                android:text="0%" />        </TableRow>    </TableLayout>    <Button        android:id="@+id/bt_startDownlode"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:onClick="startDownlode"        android:text="開始下載" /></LinearLayout>

核心代碼

package com.examp.mutildownloader;import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.text.TextUtils;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;/** * Android下的多線程下載,斷點下載 *  * @author MartinDong *  */public class MainActivity extends Activity {// sd卡的路徑private static final File sd = Environment.getExternalStorageDirectory();private static final int DOWNLODE_ERROR = 1;private static final int DOWNLODE_SUCCESS = 2;private static final int DOWNLODE_DELETE_TEMP = 3;public static final int PROGRESS_NUMBER_CHANGE = 4;// 定義線程個數private static int threadCount = 3;// 定義當前存貨的線程個數private static int runningThread = 3;// 組件的擷取private EditText et_path;private ProgressBar pb;private Button bt_startDownlode;private TextView tv_progressNumber;// 定義儲存的檔案名稱private String filename;// 設定進度條的進度// 進度條的資料public int progressTemp = 0;// 定義訊息處理private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case DOWNLODE_ERROR:Toast.makeText(getApplicationContext(), "下載失敗....",Toast.LENGTH_SHORT).show();break;case DOWNLODE_SUCCESS:// 設定按鈕可用bt_startDownlode.setEnabled(true);// 清空進度progressTemp = 0;pb.setProgress(progressTemp);// 文本清0tv_progressNumber.setText("0%");Toast.makeText(getApplicationContext(), "下載成功....",Toast.LENGTH_SHORT).show();break;case DOWNLODE_DELETE_TEMP:Toast.makeText(getApplicationContext(), "刪除進度檔案....",Toast.LENGTH_SHORT).show();break;case PROGRESS_NUMBER_CHANGE:tv_progressNumber.setText(pb.getProgress() * 100 / pb.getMax()+ "%");break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);// 擷取組件pb = (ProgressBar) findViewById(R.id.pb);bt_startDownlode = (Button) findViewById(R.id.bt_startDownlode);tv_progressNumber = (TextView) findViewById(R.id.tv_progressNumber);}public void startDownlode(View view) {// 設定按鈕不可點擊//防止重複提交bt_startDownlode.setEnabled(false);// 從控制項中擷取下載的路徑final String path = et_path.getText().toString().trim();// 擷取輸入地址的最後一個"/"出現的位置int lastIndex = path.lastIndexOf("/");// 擷取檔案名稱及格式filename = path.substring(lastIndex + 1, path.length());System.out.println("檔案名稱為===============" + filename);// 判斷路徑是否有效if (TextUtils.isEmpty(path)) {Toast.makeText(this, "請輸入有效下載路徑......", Toast.LENGTH_SHORT).show();return;}// 為了避免與主線程衝突,開啟子線程完成,避免anr問題new Thread() {public void run() {try {// 1,串連到伺服器,擷取一個檔案,擷取檔案的大小跟伺服器的檔案一樣的臨時檔案// String path = "http://172.22.64.193:8080/tomcat.css";URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 設定逾時conn.setConnectTimeout(5000);// 佈建要求方式conn.setRequestMethod("GET");// 擷取伺服器的返回碼int code = conn.getResponseCode();// 判斷返回碼if (code == 200) {// 擷取返回的長度int length = conn.getContentLength();// 設定進度條的最大值pb.setMax(length);System.out.println("檔案總長度:" + length);// 在用戶端建立出一個跟伺服器大小一致的臨時檔案RandomAccessFile raf = new RandomAccessFile(sd + "/"+ filename, "rwd");// 指定臨時檔案的大小raf.setLength(length);// 釋放資源raf.close();// 平均每一個線程的檔案大小int blockSize = length / threadCount;// 設定活躍的線程runningThread = threadCount;for (int threadId = 1; threadId <= threadCount; threadId++) {// 線程開始的下載位置int startIndex = (threadId - 1) * blockSize;// 線程的結束位置int endIndex = threadId * blockSize - 1;// 判斷是否是最後一個線程if (threadId == threadCount) {// 設定結束的位置為到檔案的最後endIndex = length;}System.out.println("線程:" + threadId+ "下載:開始位置>>>>>>>>" + startIndex+ "結束>>>>>>>>>>" + endIndex);new DownlodeThread(path, threadId, startIndex,endIndex).start();}}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}};}.start();}/** * 下載檔案的子線程類,每一個線程下載對應位置檔案資料 *  * @author MartinDong *  */public class DownlodeThread extends Thread {private String path;private int threadId;private int startIndex;private int endIndex;/** *  * @param path *            檔案的下載路徑 * @param threadId *            線程id * @param startIndex *            線程開始的位置 * @param endIndex *            線程結束的位置 */public DownlodeThread(String path, int threadId, int startIndex,int endIndex) {this.path = path;this.threadId = threadId;this.startIndex = startIndex;this.endIndex = endIndex;}@Overridepublic void run() {try {// 檢查是否存在下載曆史的檔案File tempFile = new File(sd + "/" + threadId + ".txt");// =========================斷點記錄操作===============================if (tempFile.exists() && tempFile.length() > 0) {// 檔案輸入資料流FileInputStream fis = new FileInputStream(tempFile);// 中間變數,緩衝的作用byte[] tempBuffer = new byte[1024];// 擷取進度檔案的資料大小int length = fis.read(tempBuffer);// 擷取進度檔案的資料String historyData = new String(tempBuffer, 0, length);// 將進度資料裝換為整型int historyDataInt = Integer.parseInt(historyData);// 如果是斷點傳送,初始化進度條的進度// 擷取每個線程已經下載了的進度int temp = historyDataInt - startIndex;// 為進度重新賦值progressTemp += temp;// 修改真正的下載位置startIndex = historyDataInt;fis.close();}// =========================斷點記錄操作===============================// 將地址轉換為URLURL url = new URL(path);// 擷取http串連HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 設定串連的請求方式conn.setRequestMethod("GET");// 重要:請求伺服器下載部分的檔案,指定檔案的位置conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+ endIndex);System.out.println("線程:" + threadId + "真實開始的下載進度:" + startIndex);// 設定逾時時間conn.setReadTimeout(5000);// 得到伺服器的狀態代碼,200表示請求的全部資源得到響應=== ok,206請求的部分資源得到響應=== okint code = conn.getResponseCode();System.out.println("code:" + code);if (code == 206) {// 返回的是指定位置的檔案流InputStream is = conn.getInputStream();// 建立一個臨時的檔案RandomAccessFile raf = new RandomAccessFile(sd + "/"+ filename, "rwd");// 移動指標,到指定的檔案位置,raf.seek(startIndex);// 建立中間緩衝位元組數組byte[] buffer = new byte[1024];// 讀取檔案的大小int length = 0;// 定義已經下載的資料長度,用作斷點下載的記錄=========================斷點記錄操作===============================int downlodeTotal = 0;// 迴圈寫入while ((length = is.read(buffer)) != -1) {// 定義一個記錄線程的記錄檔案=========================斷點記錄操作===============================RandomAccessFile historyFile = new RandomAccessFile(sd+ "/" + threadId + ".txt", "rwd");// 向檔案中寫入資料raf.write(buffer, 0, length);// 記錄已經下載的檔案長度downlodeTotal += length;// 將已經下載的檔案長度和開始的讀取位置相加,得到已經讀取的檔案位置historyFile.write((downlodeTotal + startIndex + "").getBytes());historyFile.close();// =========================斷點記錄操作===============================// 保持同步的更新synchronized (MainActivity.this) {// 將每個線程的讀取檔案的大小累加到下載進度上progressTemp += length;// 更新介面上的Progress的進度條的長度pb.setProgress(progressTemp);// 特殊情況ProgressBar ProgressDialog// 是可以直接在子線程中跟新ui的,內部代碼有過特殊的處理// 使用Message.obtain();減少Message對象的建立                                                        Message msg = Message.obtain();msg.what = PROGRESS_NUMBER_CHANGE;handler.sendMessage(msg);}}is.close();raf.close();System.out.println("線程:" + threadId + "下載完畢............");} else {System.out.println("線程:" + threadId+ "下載失敗請重新下載............");// 向訊息處理器發送資訊Message msg = new Message();msg.what = DOWNLODE_ERROR;handler.sendMessage(msg);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {synchronized (MainActivity.this) {// 進行線程數量的變化操作runningThread--;// 如果當前存活的線程為0,執行進度檔案統一銷毀的操作if (runningThread == 0) {// 如果下載完畢,清除進度檔案for (int threadIndex = 1; threadIndex <= threadCount; threadIndex++) {// 這裡建立的是與線程檔案對應的檔案,檔案名稱可以自訂,方便起見是採用的是線程的ID表示File temp = new File(sd + "/" + threadIndex+ ".txt");// 執行檔案刪除的操作temp.delete();}System.out.println("下載完畢,刪除進度檔案.............");// 向訊息處理器發送資訊// 向訊息處理器發送資訊Message msg = new Message();msg.what = DOWNLODE_SUCCESS;handler.sendMessage(msg);}}}}}}


Demo:

http://download.csdn.net/detail/u011936142/7428611




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.