Android 下载线程的编写

在我们的开发中,碰到文件下载的情况已经是很多见了吧?平时在开发大项目时,我们可能会用一些开源的库,比如afinal、Xutils等等,不过对于一些菜鸟的学习来说,自己去写一个下载的工具类,这对于自身的知识巩固那还是有很多好处的。好了废话不多说,现在我们直接来写一个文件下载工具类(不支持断点续传)。

下面我们来分析一下怎么去写。

首先,我们得去发送http请求去加载我们的inputStream吧,其次我们还得去利用BufferedInputStream、BufferedOutputStream等去写文件吧,还有md5校验吧。好了这里边还有很多细节问题,我们来一一查看,直接上代码。

	// 获取文件的inputStream
	private InputStream getInputStream(String path)throws Exception {
		listener.statusListener(0,this.getFileName());
		URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(10 * 1000);
		conn.setRequestMethod("GET");
		
		if(length <= 0){
			try {
				Map<String, List<String>> map = conn.getHeaderFields();
				for(int i=0;i<map.size();i++){
					if(map.containsKey("Content-Length")){
						String temp = map.get("Content-Length").toString().replaceAll("\\]", "").replaceAll("\\[", "");
						length = Long.parseLong(temp);
						break;
					}
				}
			} catch (Exception e) {
				length = 0;
			}
		}
		
		if(length <= 0){
			listener.statusListener(-1,this.getFileName());
			return null;
		}
		if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
			return conn.getInputStream();
		}
		return null;
	}

根据上面的代码块我们来分析,HttpURLConnection去拿我们想要的数据,包括http头和inputStream,在http头里边有我们下载文件的长度,这个长度可以用来检测下载成功与否和下载进度的显示。这个方法我们返回的是一个inputStream。

在线程run方法里边有一个while循环,在循环里去获取inputStream,因为有可能我们获取到的inputStream为null,所以我们循环获取,最多获取三次。

		while (isRunning && errorCount < 3) {
			threadStartRun = true;
			if(errorCount >= 2){
				listener.statusListener( -1,this.getFileName());
				break;
			}
			try {
				inputStream = getInputStream(src);
				if(inputStream == null){
					errorCount++;
					Thread.sleep(3000);
					continue;
				}
			} catch (Exception e) {
				e.printStackTrace();
				errorCount++;
				continue;
			}
			if(inputStream !=null){
				break;
			}
		}
拿到inputStream之后当然是去读写文件到本地.
	/**
	 * 将InputStream保存为本地文件
	 * */
	private String saveFile(InputStream is) throws IOException {
		threadStartWrite = true;
		File myCaptureFile = new File(this.getFileName());

		if (myCaptureFile.exists()) {
			myCaptureFile.delete();
		}
		myCaptureFile.createNewFile();
		FileOutputStream out = null;
		try {
			out = new FileOutputStream(myCaptureFile);
			BufferedInputStream bufis = new BufferedInputStream(is);
			BufferedOutputStream bufos = new BufferedOutputStream(out);
			byte[] b = new byte[1024*16];
			int len;
			long count = 0;
			float process = 0;
			while (isRunning && (len = bufis.read(b)) != -1) {
				bufos.write(b, 0, len);
				count += len;
				process =(float)count/length*100;
				if(!isRunning){
					break;
				}
				getListener().statusListener((int)process,myCaptureFile.getAbsolutePath());
				downprocess = (int)process;
				N = (int) count;
			}
			out.flush();
			bufis.close();
			bufos.close();
			if(!isRunning){
				return null;
			}
			String tempMd5 = getFileMD5(myCaptureFile);
			if(!(getMd5().equals(tempMd5))){
				N = -1;
				downprocess = -1;
				return null;
			}
			return myCaptureFile.getAbsolutePath();
		} catch (Exception e) {
			getListener().statusListener(-1,myCaptureFile.getAbsolutePath());
			N = -1;
			downprocess = -1;
			return null;
		}
	}
从上面代码块我们可以看到,获取到inputStream之后利用BufferedInputStream等去写文件,当然还有一个重要方法就是getListener().statusListener((int)process, myCaptureFile. getAbsolutePath());通知调用者当前下载的进度。

下载完成之后会有一个md5码的校验,直接来代码。若返回为null校验失败,否则下载成功。

	private String getFileMD5(File file) {
		if (!file.isFile()) {
			return null;
		}
		MessageDigest digest = null;
		FileInputStream in = null;
		byte buffer[] = new byte[1024];
		int len;
		try {
			digest = MessageDigest.getInstance("MD5");
			in = new FileInputStream(file);
			while ((len = in.read(buffer, 0, 1024)) != -1) {
				digest.update(buffer, 0, len);
			}
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		BigInteger bigInt = new BigInteger(1, digest.digest());
		String strMd5 = bigInt.toString(16);
		if (strMd5.length() < 32) {
			for (int i = 0; i < 32 - strMd5.length(); i++) {
				strMd5 = "0" + strMd5;
			}
		}
		return strMd5;
	}
当然下载完成之后我们还得通知调用者下载完成吧。

getListener().statusListener(100,myCaptureFile.getAbsolutePath());

好了,下载的线程算是完事了,我们的额超时线程还没完呢,等等,别着急马上。它主要是干啥呢,就是检测下载线程的运行状态,来吧那就。

	@Override
	public void run() {
		super.run();
		name = downloadTask.getFileName();
		try {
			while(!downloadTask.isThreadStartRun()&& downloadTask.isRunning()){ //开始启动下载的时候 ,超时线程也跟着启动。
				Thread.sleep(500);
			}
			if(downloadTask.isRunning()){
				isWhile = true;
			}
			Thread.sleep(2000);
			while(downloadTask != null && downloadTask.isRunning()) {
				isWhile = true;
				Thread.sleep(3000);
				if(c != downloadTask.getN() && downloadTask.isThreadStartWrite() && c!=downloadTask.getLength()) {
					c = downloadTask.getN();
					t=0;
					process = downloadTask.getDownprocess();
				} else {
					if(process<100)t++;
				}
				process = downloadTask.getDownprocess();
				if(process > 100){
					break;
				}
				if(t >= TIMEOUT_COUNT) {
					downloadTask.setRunning(false);
					downloadTask.interrupt();
					downloadTask = null;
					break;
				}
				if(process <= -1){
					break;
				}
			}
			if(t >= TIMEOUT_COUNT && downloadTask == null && process<100) {
				listener.statusTimeoutListener(-1,name);
				return;
			}
			if(!isWhile){
				if(downloadTask != null){
					downloadTask.setRunning(false);
					downloadTask.interrupt();
					downloadTask = null;
				}
				listener.statusTimeoutListener(-1,name);
			}
		} catch (Exception e) {
			if(process <100){
				listener.statusTimeoutListener(process,name);
			}
		}

这是它的一个run方法,可以看到首先,做一个延时,等待下载线程的执行,因为我们的超时线程和下载线程必须同时执行!!随之来的就是检测,检测下载线程的isRunning,检测文件读写是是否卡顿,如果在12s之内下载一直是卡顿的,我们就直接将下载线程停止掉(当然,这个停止掉指的是我们不再使用它,并不能直接杀死他),这个12秒我们也可以自己在超时线程里边控制。如果 listener.statusTimeoutListener(process,name);则表示线程下载超时,停止下载。

使用方法:

		DownloadTask downloadTask = new DownloadTask("下载地址", "文件md5", 122222, "文件保存地址", new DownloadTask.DownLoadTaskStatusListener() <span style="white-space:pre">			</span>{
			public void statusListener(int process, String fileName) {
				// 这里边是下载进度的回调
			}
		});
		downloadTask.start();
		DownloadTimeout downloadTimeout = new DownloadTimeout(downloadTask, new DownLoadTaskStatusTimeoutListener() {
			public void statusTimeoutListener(int process, String fileName) {
				// 这里边是下载失败,超时的回调
			}
		});
		downloadTimeout.start();

当然咯,下面就是下载链接了 点击打开链接 下载。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值