package com.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.Handler; import android.os.Message; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.tenone.androidtest.R; public class MainActivity extends Activity { protected static final int DOWN_LOAD_ERROR = 0; public static final int DOWN_LOAD_FINISH = 1; protected static final int SERVICE_ERROR = 2; public static final int UPDATE_TEXT = 3; public static int threadCount = 3; public static int runningThread = 3; private EditText et_path; private ProgressBar pb; private TextView tv_process; public int currentPross;//當前的進度 private Handler handler = new Handler(){ @Override public void handleMessage(Message msg){ switch (msg.what){ case DOWN_LOAD_ERROR: Toast.makeText(getApplicationContext(), "下載失敗", 0).show(); break; case DOWN_LOAD_FINISH: Toast.makeText(getApplicationContext(), "下載完成", 0).show(); break; case SERVICE_ERROR: Toast.makeText(getApplicationContext(), "服務器出錯", 0).show(); break; case UPDATE_TEXT: tv_process.setText("當前進度:"+pb.getProgress()*100/pb.getMax()); break; } } }; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.loader_layout); et_path = (EditText) findViewById(R.id.loader_text); pb = (ProgressBar) findViewById(R.id.loader_pb); tv_process = (TextView) findViewById(R.id.tv_process); } public void downLoad(View v){ final String path = et_path.getText().toString().trim(); if (TextUtils.isEmpty(path)){ Toast.makeText(this, "下載路徑錯誤", 0).show(); return ; } new Thread(){ public void run(){ //1.鏈接服務器,獲取一個文件並獲取該文件的大小 //在本地建立一個大小跟服務器文件同樣大的臨時文件 try { //String path = "http://w.x.baidu.com/alading/anquan_soft_down_normal/13478/npp.6.6.9.Installer.1410249599.exe"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); System.out.println("codemain:"+code); if (code == 200){ //服務器返回的數據長度,其實是文件的長度 int length = conn.getContentLength(); pb.setMax(length);//設置進度條的最大值 System.out.println("文件總長度:"+length); //在客戶端本地建立出一個和服務器端大小同樣的文件 RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe", "rwd"); //指定建立的這個文件的長度 raf.setLength(length); raf.close(); //計算出每一個線程下載的文件大小 int blockSize = length / 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 DownloadThread(threadId, startIndex, endIndex, path).start(); } }else{ Message msg = new Message(); msg.what = SERVICE_ERROR; handler.sendMessage(msg); System.out.println("服務器錯誤"); } } catch (Exception e) { e.printStackTrace(); Message msg = new Message(); msg.what = DOWN_LOAD_ERROR; handler.sendMessage(msg); } } }.start(); } public class DownloadThread extends Thread{ private int threadId; private int startIndex; private int endIndex; private String path; public DownloadThread(int threadId, int startIndex, int endIndex, String path) { super(); this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; this.path = path; } @Override public void run(){ try { //檢查是否存在記錄下載長度的文件,若是存在讀取這個文件的數據 File tempFile = new File("/sdcard/"+threadId+".txt"); if (tempFile.exists() && tempFile.length()>0){ FileInputStream fis = new FileInputStream(tempFile); byte[] temp = new byte[1024]; //讀取長度爲temp長度的數據到temp中,返回的是讀取數據的長度,讀到文件末尾返回-1 int leng = fis.read(temp); String downloadLen = new String(temp, 0, leng); int downloadlenInt = Integer.parseInt(downloadLen); int alreadyDownloadint = downloadlenInt - startIndex; currentPross+=alreadyDownloadint;//獲取已經下載的進度 startIndex = downloadlenInt;//修改下載的真實的開始位置 System.out.println("線程"+threadId+"真實下載位置:"+startIndex+"--->"+endIndex); fis.close(); } URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); //請求服務器下載部分文件指定文件的位置 conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex); conn.setReadTimeout(5000); /* * 從服務器請求所有資源200 ok * 若是從服務器請求部分資源206 ok * */ int code = conn.getResponseCode(); System.out.println("code:"+code); //已經設置了請求的位置,返回的是當前位置對應的文件輸入流 InputStream is = conn.getInputStream(); RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe", "rwd"); //隨機寫文件的時候從哪一個位置開始寫 raf.seek(startIndex); int len = 0; byte[] buffer = new byte[1024]; //已經下載的數據 int total = 0; //記錄當前線程下載數據的長度(方法一) //File file = new File(threadId+".text"); while ((len = is.read(buffer)) != -1){ //FileOutputStream fos = new FileOutputStream(file); //方法二 RandomAccessFile info = new RandomAccessFile("/sdcard/"+threadId+".txt", "rwd"); raf.write(buffer, 0, len); total+=len; info.write(String.valueOf(total+startIndex).getBytes()); info.close(); synchronized (MainActivity.this){ currentPross+=len;//獲取當前的總進度 pb.setProgress(currentPross);//更改界面上progressbar進度條的進度 //特殊狀況progressbar progressdialog進度條對話框能夠直接在子線程裏 //更新ui 內部代碼特殊處理 //複用舊的消息避免過多的建立消息 Message msg =Message.obtain(); msg.what = UPDATE_TEXT; handler.sendMessage(msg); } //fos.write(String.valueOf(total).getBytes()); //fos.close(); } is.close(); raf.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ threadFinish(); } } private synchronized void threadFinish() { runningThread--; if (runningThread == 0){//全部線程下載完成 for (int i=1; i<=3; i++){ File file = new File("/sdcard/"+i+".txt"); file.delete(); } System.out.println("文件下載完畢,刪除全部的下載記錄"); Message msg = new Message(); msg.what = DOWN_LOAD_FINISH; handler.sendMessage(msg); } } } }