天天看點

android 單線程 多線程下載下傳

單線程下載下傳很簡單,就是開啟一個線程去下載下傳資源再進行本地儲存;

多線程下載下傳是通過RandomAccessFile(随機檔案讀寫操作類)來設定每個線程讀取檔案的起始點位置,起始點之間的長度即為該線程需要下載下傳的檔案大小

下載下傳開始位置:線程id*每條線程下載下傳的資料長度 = ?

下載下傳結束位置:(線程id+1)*每條線程下載下傳的資料長度-1=?

這樣比如檔案大小:size,線程數:threads,則每個線程的下載下傳量:size/threads;但是這是整除的情況,如果考慮到不能整除的情況:則前threads-1個線程下載下傳量為size/threads,最後一個線程的下載下傳量:size/threads+size%threads

package file.down;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import javax.security.auth.PrivateCredentialPermission;

import android.R.integer;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewDebug.FlagToString;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;

public class File_downActivity extends Activity {
	private Button but1,but2;
	private EditText etUrl;
	private ProgressBar bar1,bar2;
	private TextView tv1,tv2;
	private boolean flag = true;
	private int temp = 0;
	private int downLoadedSize = 0;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        etUrl = (EditText) findViewById(R.id.downloadUrl);
        
        but1 = (Button) findViewById(R.id.but1);
        but2 = (Button) findViewById(R.id.but2);
        
        bar1 = (ProgressBar) findViewById(R.id.downloadProgressBar1);
        bar2 = (ProgressBar) findViewById(R.id.downloadProgressBar2);
        
        tv1 = (TextView) findViewById(R.id.tv1);
        tv2 = (TextView) findViewById(R.id.tv2);
        
        
        //單線程下載下傳
        but1.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				if(DownUtil.isExistSdCard()){
					if(DownUtil.checkNet(File_downActivity.this)){
						if(DownUtil.creatDir(DownUtil.path1)){
							thread.start();
						}
					}
				}
			}
		});
        //多線程下載下傳
        but2.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				mulThread.start();
			}
		});
    }
    @Override
    protected void onDestroy() {
    	super.onDestroy();
    	DownUtil.downLoadSize = 0;
    }
    /**
     * 單線程下載下傳
     */
    private Thread thread = new Thread(new Runnable() {
		
		@Override
		public void run() {
				
				DownUtil.fileDown1(etUrl.getText().toString(), DownUtil.savePath1, handler);
				bar1.setMax(DownUtil.fileSize);
		}
	});
    /**
     * 多線程下載下傳(主線程類)
     */
    private Thread mulThread = new Thread(new Runnable() {
		private int blockSize,downLoadSizeMore;
		private int threadNum = 5;//線程數
		
		@Override
		public void run() {
//			MulDownThread[] threads = new MulDownThread[threadNum];
			try {
				URL url = new URL(etUrl.getText().toString());
				URLConnection connection = url.openConnection();
				DownUtil.fileSize2 = connection.getContentLength();
				if(DownUtil.fileSize2 <= 0){
					return;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			//計算每個線程下載下傳的資料量
			blockSize = DownUtil.fileSize2 / threadNum;
			//解決整除後餘下的資料量
			downLoadSizeMore = DownUtil.fileSize2 % threadNum;
			bar2.setMax(100);
			if(DownUtil.creatDir(DownUtil.path2)){
				
				File file = new File(DownUtil.savePath2 + "/" + etUrl.getText().toString().substring(etUrl.getText().toString().lastIndexOf("/") + 1));
				for(int i=0;i<threadNum;i++){
					if(i < threadNum - 1){
						
						//啟動線程,分别下載下傳檔案
						MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize - 1,handler);
						thread.start();
					}else{//最後那個線程下載下傳的檔案長度要等于每個線程平均下載下傳量加上整除後的餘數
						MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize - 1 + downLoadSizeMore,handler);
						thread.start();
					}
//					//啟動線程,分别下載下傳檔案
//					MulDownThread thread = new MulDownThread(etUrl.getText().toString(), file, i*blockSize, (i + 1) * blockSize -1);
//					thread.start();
//					handler.sendEmptyMessage(10);
				}
//				boolean finished = false;
//				while(!finished){
//					//先把整除的餘數搞定
//					downLoadedSize = downLoadSizeMore;
//					finished = true;
//					for(int i = 0;i<threads.length;i++){
//						downLoadedSize += threads[i].downLoadSize;
//						if(!threads[i].isFinisthed){
//							finished = false;
//						}
//					}
//					handler.sendEmptyMessage(10);
//				}
			}
		}
	});
    private Handler handler = new Handler(){
    	public void handleMessage(android.os.Message msg) {
    		switch (msg.what) {
			case 0:
				tv1.setText("無法擷取檔案大小");
				break;
			case -1:
				tv1.setText("下載下傳完成");
				bar1.setProgress(100);
				but1.setClickable(false);
			    break;

			case 1:
				but1.setClickable(false);
				int result = Double.valueOf(((Integer.parseInt(msg.obj.toString())*1.0 / DownUtil.fileSize * 100))).intValue();
				bar1.setProgress(result);
				tv1.setText(result + "%");
				break;
			case 2:
				tv1.setText("檔案擷取錯誤");
				break;
		    case 10://多線程下載下傳更新進度條
		    	but2.setClickable(false);
		    	int result2 = (Double
						.valueOf((Integer.parseInt(msg.obj.toString()) * 1.0 / DownUtil.fileSize2 * 100)))
						.intValue();
		    	bar2.setProgress(result2);
		        if(result2 == 100){
		        	tv2.setText("下載下傳完成");
		        }else{
		        	
		        	tv2.setText(result2 + "%");
		        }
		    	break;
			}
    	};
    };
}
           
package file.down;

import java.io.File;

import android.os.Handler;
/**
 * 線程類
 * @author Administrator
 *
 */
public class MulDownThread extends Thread {

	private String url;
	private File file;
	private int startPosition;
	private int endPosition;
	private Handler handler;
	
	
	public MulDownThread(String url,File file,int startPosition,int endPosition,Handler handler){
		this.url = url;
		this.file = file;
		this.startPosition = startPosition;
		this.endPosition = endPosition;
		this.handler = handler;
	}
	
	@Override
	public void run() {
		DownUtil.fileDown2(url, file, startPosition, endPosition,handler);
	}

	
	
}
           
package file.down;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import android.R.integer;
import android.R.string;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class DownUtil {

	//單線程下載下傳目錄
	public static String path1 = "/down1/";
	public static String savePath1;
	//多線程下載下傳目錄
	public static String path2 = "/down2/";
	public static String savePath2;
	
	public static String fileName;
	public static int fileSize;
	public static int fileSize2;
	
	private static int curPosition;
	//已下載下傳的檔案大小
	public static int downLoadSize;
	//标示目前線程是否下載下傳完成
	public static boolean finished = false;
	/**
	 * 判斷sd卡是否存在
	 * Environment.MEDIA_MOUNTED 判斷SD卡是否存在
	 * @return
	 */
	public static boolean isExistSdCard(){
		boolean flag = true;
		if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
			flag = false;
		}
		return flag;
	}
	/**
	 * 建立目錄
	 * @param dir
	 * @return
	 */
	public static boolean creatDir(String dir){
		boolean flag = false;
		File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + dir);
		if(!file.exists()){
			file.mkdir();
			if(file.exists()){
				flag = true;
				savePath1 = file.getAbsolutePath();
				savePath2 = file.getAbsolutePath();
			}
		}else{
			flag = true;
			savePath1 = file.getAbsolutePath();
			savePath2 = file.getAbsolutePath();
		}
		return flag;
	}
	/**
	 * 檢查網絡是否可用
	 * @return
	 */
	public static boolean checkNet(Context context){
		boolean flag = false;
		ConnectivityManager manager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
		NetworkInfo wifi = manager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
		NetworkInfo mobile = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
		if(wifi.isConnectedOrConnecting() || mobile.isConnectedOrConnecting()){
			flag = true;
		}
		return flag;
	}
	/**
	 * 單線程檔案下載下傳
	 * @param url
	 * @param path
	 */
	public static void fileDown1(String url,String path,Handler handler) {
		Log.v("=path=", path+"=");
		Message message = new Message();
		if(!"".equals(url)){
			fileName = url.substring(url.lastIndexOf("/") + 1);
			InputStream inputStream = null;
			FileOutputStream outputStream = null;
			try {
				URL myuUrl = new URL(url);
				URLConnection connection = myuUrl.openConnection();
				connection.connect();
				inputStream = connection.getInputStream();
				fileSize = connection.getContentLength();
				Log.v("=fileSize=", DownUtil.fileSize+"=");
				if(fileSize <= 0){
					message.what = 0;
					handler.sendMessage(message);
					return;
				}else{
					outputStream = new FileOutputStream(path +"/"+ fileName);
					//存儲檔案
					byte buf[] = new byte[inputStream.available()];
					int len = 0;
					int temp = 0;
					Log.v("=available=", inputStream.available()+"=");
					while ((len = inputStream.read(buf)) != -1) {
						outputStream.write(buf, 0, len);
						temp += len;
						Message message2 = new Message();
						message2.what = 1;
						message2.obj = temp;//下載下傳的百分比
						handler.sendMessage(message2);
					}
					Message msg = new Message();
					//通知下載下傳完成
					msg.what = -1;
					handler.sendMessage(msg);
				}
			} catch (Exception e) {
				message.what = 2;
				handler.sendMessage(message);
				return;
			}finally{
				try {
					
					if(inputStream != null || outputStream != null){
						outputStream.close();
						inputStream.close();
					}
				} catch (Exception e2) {
				}
			}
		}
	}
	/**
	 * 多線程下載下傳檔案
	 * @param url
	 * @param path
	 * @param handler
	 */
	public static void fileDown2(String url,File file,int startPosition,int endPosition,Handler handler){
		URLConnection connection = null;
		InputStream inputStream = null;
		BufferedInputStream bis = null;
		RandomAccessFile raf = null;
		try {
			URL url2 = new URL(url);
			connection = url2.openConnection();
//			connection.connect();
			connection.setAllowUserInteraction(true);
			// 設定目前線程下載下傳的起點,終點
			connection.setRequestProperty("Range", "bytes=" + startPosition + "-"
					+ endPosition);
			inputStream = connection.getInputStream();
			if(fileSize2 <= 0){
				return;
			}
			//對檔案進行随機讀寫操作
			raf = new RandomAccessFile(file,"rw");
			//設定開始寫檔案的位置
			raf.seek(startPosition);
			bis = new BufferedInputStream(inputStream);
			//開始循環以流的形式讀寫檔案
//			curPosition = startPosition;
			//每個線程需要讀取檔案的長度
//			int temp = endPosition - startPosition;
			byte[] buffer = new byte[1024];
			int length = 0;
			while ((length = inputStream.read(buffer)) != -1) {
				raf.write(buffer, 0, length);
				downLoadSize += length;
				Message message = new Message();
				message.what = 10;
				message.obj = downLoadSize;
				handler.sendMessage(message);
			}
//			while (curPosition < endPosition) {
//				int len = bis.read(buffer, 0, temp);
//				if(len == -1){
//					break;
//				}
//				Log.v("=len=", "="+len);
//				raf.write(buffer, 0, len);
//				curPosition += len;
				if(curPosition > endPosition){
					downLoadSize += len - (curPosition - endPosition) + 1;
					Log.v("=downLoadSize=", "="+downLoadSize);
				}else{
//					downLoadSize += len;
				}
//					Message message = new Message();
//					message.what = 10;
//					message.obj = downLoadSize;
//					handler.sendMessage(message);
//			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(inputStream != null || raf != null || bis != null){
					bis.close();
					raf.close();
					inputStream.close();
				}
			} catch (Exception e2) {
			}
		}
	}
}