Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android----斷點多線程下載

android----斷點多線程下載

編輯:關於Android編程

在tomcat6.0的webappsROOT下放一個.exe的可執行文件(若放.mp3、.jpg等格式的文件可能下載過程出現損壞還是可以查看的,若是.exe可執行文件下載過程出現損壞就不可執行了),然後啟動tomcat,雙擊bin文件夾下的startup.bat,出現以下的界面

\

記得不要關閉這個窗體,若關閉了後面的文件下載會出錯的。

Android的布局文件代碼如下:

 



    

    

效果如下圖:

 

\

為了方便,在代碼中寫死了下載路徑。

MainActivity中的代碼如下:

 

package com.myself.download;

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.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
	protected static final int DOWN_LOAD_ERROR = 1;
	protected static final int SERVER_ERROR = 2;
	protected static final int SD_UNABLE = 3;
	public static final int DOWN_LOAD_FINISH = 4;
	public static final int UPDATE_TEXT = 5;
	public static int threadCount = 3;
    public static int runingThread =3;
    
    public int currentProcess=0;//當前的進度
    
	private EditText et_path;
	private ProgressBar pb;
	private TextView tv_show;
	
	private Handler handler=new Handler(){
         public void handleMessage(android.os.Message msg) {
        	 switch (msg.what) {
			case DOWN_LOAD_ERROR:
				Toast.makeText(MainActivity.this, 下載錯誤, 1).show();
				break;
			case SERVER_ERROR:
				Toast.makeText(MainActivity.this, 服務器連接錯誤, 1).show();
				break;
			case SD_UNABLE:
				Toast.makeText(MainActivity.this, SD卡不可用, 1).show();
				break;
			case DOWN_LOAD_FINISH:
				Toast.makeText(MainActivity.this, 資源下載完畢, 1).show();
				break;
			case UPDATE_TEXT:
				tv_show.setText(目前下載的進度:+pb.getProgress()*100/pb.getMax()+%);
				break;
			default:
				break;
			}
         };
	};

	@Override
	protected 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);
		tv_show=(TextView) findViewById(R.id.tv_show);
	}

	public void download(View v){
		final String path=et_path.getText().toString().trim();
		if(TextUtils.isEmpty(path)){
			Toast.makeText(this, 下載路徑不能為空, 1).show();
			return ;
		}
		new Thread(){
			public void run() {
				// 1.連接服務器,獲取要下載的文件長度,並創建一個跟要下載資源大小一樣的臨時文件
				try {
					
					//String path = http://172.29.168.1:8088/fengxing.exe;
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setConnectTimeout(5000);
					conn.setRequestMethod(GET);
					int code = conn.getResponseCode();
					System.out.println(code:   +code);
					if (code == 200) {
						// 服務器返回的數據的長度實際上就是文件的長度
						int length = conn.getContentLength();
						pb.setMax(length);
						//System.out.println(文件總長度: + length);
						//判斷sd卡是否可用
						if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
							//在客戶端創建一個與要下載的資源同樣大小的臨時文件
							RandomAccessFile raf=new RandomAccessFile(/sdcard/fengxing.exe, rwd);
							//設置文件的大小
							raf.setLength(length);
							raf.close();
							
							
							// 假設是3個線程去下載
							// 平均每一個線程下載的資源的大小
							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 DownlLoad(threadId, startIndex, endIndex, path).start();
								
							}
						}else{
							System.out.println(sd卡不可用...);
							Message msg=new Message();
							msg.what=SD_UNABLE;
							handler.sendMessage(msg);
						}
						
					} else {
						System.out.println(服務器連接錯誤...);
						Message msg=new Message();
						msg.what=SERVER_ERROR;
						handler.sendMessage(msg);
					}

				} catch (Exception e) {
					e.printStackTrace();
					Message msg=new Message();
					msg.what=DOWN_LOAD_ERROR;
					handler.sendMessage(msg);
				}
				
			};
		}.start();
	}
	
	/**
	 * 下載文件的子線程   每一個線程下載對應位置的文件
	 * @author Administrator
	 *
	 */
	public class DownlLoad extends Thread{
		private int threadId;
		private int startIndex;
		private int endIndex;
		private String path;
		
		/**
		 * 
		 * @param threadId 線程Id
		 * @param startIndex  開始下載的位置
		 * @param endIndex  結束位置
		 * @param path 要下載的資源所在路徑
		 */
		public DownlLoad(int threadId, int startIndex, int endIndex, String path) {
			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];
					int leng=fis.read(temp);
					String downloadLen=new String(temp,0,leng);
					int downloadInt=Integer.parseInt(downloadLen);
					
					int alreadyDownInt=downloadInt-startIndex;//已經下載的進度
					currentProcess+=alreadyDownInt;//若已經有下載的,重新設置進度
					
					startIndex=downloadInt;//修改下載真實的開始位置
					
				}
				
				
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5000);
				conn.setRequestMethod(GET);
				//重要:請求服務器下載部分的文件  指定下載的資源范圍
				conn.setRequestProperty(Range, bytes=+startIndex+-+endIndex);
				System.out.println(線程+threadId+線程重新開始下載的位置: +startIndex+------->+endIndex);
				int code = conn.getResponseCode();//200代表的是全部的資源     206代表的是部分資源
				
				//System.out.println(code:+code);
				if(code==206){
					InputStream is=conn.getInputStream();//已經設置了請求的位置  返回當前位置對應的文件的輸入流
					RandomAccessFile raf=new RandomAccessFile(/sdcard/fengxing.exe, rwd);
					raf.seek(startIndex);//定位開始位置
					
					int len=0;
					byte[] buff=new byte[1024];
					
					int total=0;//記錄已經下載的文件的長度
					
					while((len=is.read(buff))!=-1){
						//FileOutputStream fos=new FileOutputStream(file);
						RandomAccessFile file=new RandomAccessFile(/sdcard/+threadId+.txt,rwd);//記錄當前線程下載的長度
						raf.write(buff, 0, len);
						total+=len;
						//System.out.println(線程+threadId+   下載長度:+total);
						file.write((+(total+startIndex)).getBytes());
						file.close();
						//更新進度條
						synchronized (MainActivity.this) {
							currentProcess+=len;//獲取所有線程下載的總進度
							pb.setProgress(currentProcess);//更改進度條的進度
							
							Message msg=Message.obtain();//復用舊的消息
							msg.what=UPDATE_TEXT;
							handler.sendMessage(msg);
						}
						
					}
					is.close();
					raf.close();
					System.out.println(線程+threadId+下載完畢...);
					
					
				}else{
					System.out.println(線程+threadId+下載失敗...);
				}
				
				/*File deleteFile=new File(threadId+.txt);
				deleteFile.delete();*/
				
			} catch (Exception e) {
				e.printStackTrace();
			} finally{
				threadFinish();
			}
		}

		private synchronized void threadFinish() {
			//這部分的作用:防止某一個記錄文件在資源下載完後沒有被刪除
			runingThread--;
			if(runingThread==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);
			}
		}
	}

}

運行的效果圖:

 

\

在下載的過程中,退出程序,然後在打開程序,程序會接著在原來的基礎上繼續下載。

最後打開File Explor中的sdcard,就會發現下載的文件:

\

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved