多線程斷點下載文件

多線程斷點下載文件
1.創建Android工程,設置佈局文件.(進度條:progressBar)
2.在主Activity中實現點擊事件
public class MultiDownloadActivity extends Activity {
EditText et_path;
ProgressBar pb;
TextView tv_progress;
int totallength;
public static final int threadnumber = 3;
public static int intprocess;
Handler handler = new Handler(){

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int process = (Integer) msg.obj;
    float result = (float)process /(float)totallength;
    int text = (int)(result*100);
tv_progress.setText(text+"%");
}
};
@Override
    public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
et_path = (EditText) this.findViewById(R.id.et_path);
pb = (ProgressBar) this.findViewById(R.id.pb);
tv_progress = (TextView) this.findViewById(R.id.tv_progress);
    }
    
    // 按鈕的點擊事件
    public void download(View view){
new DownLoadThread().stop =false;
// 根據地址 下載 文件 
String path = et_path.getText().toString();
if("".equals(path)){
Toast.makeText(this, R.string.input_download_path, 1).show();
return;
}
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
// 服務器文件的總長度
totallength = conn.getContentLength();
System.out.println("文件的總長度 " + totallength);
pb.setMax(totallength);
// 在本地創建一個文件 文件大小跟服務器上文件的大小相同
File file = new File("/mnt/sdcard/"+getFileName(path));
RandomAccessFile accessfile = new RandomAccessFile(file, "rwd");
accessfile.setLength(totallength);
accessfile.close();
// 每一個線程下載的文件的大小
int blocksize;
if (totallength % threadnumber == 0) {
blocksize = totallength / threadnumber;
} else {
blocksize = totallength / threadnumber + 1;
}
// 開啓若干個線程
for (int i = 0; i < threadnumber; i++) {
new DownLoadThread(i, file, blocksize, path, totallength,pb,handler).start();
}
} catch (Exception e) {
Toast.makeText(this, R.string.error, 1).show();
e.printStackTrace();
}
    }
    
    

/**
 * 獲取文件的名字
 
 * @param path2
 *            文件的路徑
 * @return
 */
private static String getFileName(String path2) {
int start = path2.lastIndexOf("/") + 1;
return path2.substring(start);
}
//停止所對應的點擊事件 
public void stop(View view){
new DownLoadThread().stop =true;
}
}
3.調用DownLoadThread類
public class DownLoadThread extends Thread{
// 線程id
private int threadId;
// 下載的數據存放到哪個文件
private File file;
// 下載文件的大小
private int blocksize;
// 服務器文件的路徑
private String filepath;
// 文件的總長度
private int totallength;
// 下載的進度 
public static int intprocess;
//下載的進度條
ProgressBar pb;
//flag 標示符 用來停止線程
public  boolean stop = false;
//Hander 的引用
Handler handler;
public DownLoadThread(){
}
public DownLoadThread(int threadId, File file, int blocksize,
String filepath, int totallength,ProgressBar pb ,Handler handler) {
this.threadId = threadId;
this.file = file;
this.blocksize = blocksize;
this.filepath = filepath;
this.totallength = totallength;
this.pb=pb;
this.handler = handler;
}

@Override
public void run() {
try {
// 線程開啓的時候 根據當前的線程id創建一個文件 ,記錄當前線程的下載的進度
File infofile = new File("/mnt/sdcard/"+threadId + ".txt");
URL url = new URL(filepath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
int startPosition = threadId * blocksize;
int endPosition = (threadId + 1) * blocksize - 1;
if (endPosition >= totallength) {
// 設置最後一個線程的下載位置
endPosition = totallength - 1;
}
// 存放下載進度的文件是存在的
if (infofile.exists()) {
FileInputStream fis = new FileInputStream(infofile);
byte[] size = new byte[8];
int l = fis.read(size);
if (l > 0) {
startPosition = Integer.parseInt(new String(size, 0, l));
}
fis.close();
}

// HttpURLConnection.setRequestProperty("Range",
// "bytes=2097152-4194303");
conn.setRequestProperty("Range", "bytes=" + startPosition + "-"
+ endPosition);
System.out.println("線程id爲" + threadId + "開始位置 " + startPosition
+ " 結束位置 " + endPosition);
RandomAccessFile accessfile = new RandomAccessFile(file, "rwd");
accessfile.seek(startPosition);

// 循環的把服務器上的數據寫到本地
InputStream is = conn.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;

while ((len = is.read(buffer)) != -1) {
if(stop){
is.close();
return;
}
accessfile.write(buffer, 0, len);
// 記錄當前讀到的數據的開始位置
startPosition += len;
synchronized (DownLoadThread.this) {
intprocess +=len;
pb.setProgress(intprocess);
Message msg = new Message();
msg.obj = intprocess;
handler.sendMessage(msg);
}
FileOutputStream fos = new FileOutputStream(infofile);
fos.write((startPosition + "").getBytes());
fos.flush();
fos.close();
}
is.close();
accessfile.close();
System.out.println("線程" + threadId + "下載完畢");
if(infofile.exists()){
//刪除掉 記錄下載進度的文件 
System.out.println(infofile.getName()+ " 刪除 "+ infofile.delete());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.關於Handler message
   handler:就是在其他線程中操作主線程
   view對象只能被創建他的線程所修改
   一般來說.所有的顯示在主界面的控件都是主線程創建的.(main).只有主線程才能修改view對象的線程.
   onCteate()方法運行在主線程中.裏面有setContentVIew()方法.所以顯示在主界面的控件都是有主線程創建的.
   主線程中有維護消息的消息隊列(message queue),在消息隊列中有個looper(輪訓器),他會不停的查看消息隊列.
   當消息隊列中有消息的時候looper會將其取出發送給Handler處理.
   Handler是在主線程中創建的消息處理器.專門用來處理looper發來的消息.
   Handler中有handleMessage()方法.該方法運行在主線程中.他可以時時的更新UI.
   怎麼使用一個子線程控制一個UI呢.先定義一個message的消息類型,使用handleer發送一條消息給消息隊列.
   然後looper取出交給handleMessage()方法處理. 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章