`
whoyuhui
  • 浏览: 22787 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

android多线程下载详解

阅读更多

本文将介绍在android平台下如何实现多线程下载,大家都知道,android平台使用java做为开发语言,所以java中支持的多线程下载方式在android平台下都支持,其中主要有两种方式可以实现多线程下载。

一种方式是使用很多个线程分别下载文件的不同部分,最后把所有下载完的文件合并成一个文件。另一种方式是使用java为我们提供的RandomAccessFile类实现多线程的下载。

从性能上分析,第二种方式的存取速度会慢一些,但开发起来较为容易,不需要进行合并文件等操作。本文将使用第二种方式来实现多线程下载,最终效果如下图所示:

 

 

 

第一步,我们先写一个线程类,来完成对指定区域的数据进行下载,如下所示:

 

package com.ideasandroid.demo;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
 
import android.util.Log;
/**
 *  Copyright (C) 2010 ideasandroid
 *  演示android多线程下载
 *  欢迎访问http://www.ideasandroid.com
 *  让程序开发不再那么神秘
 *  
 *  单个下载线程
 */
public class FileDownloadThread extends Thread{
	private static final int BUFFER_SIZE=1024;
	private URL url;
	private File file;
	private int startPosition;
	private int endPosition;
	private int curPosition;
	//用于标识当前线程是否下载完成
	private boolean finished=false;
	private int downloadSize=0;
	public FileDownloadThread(URL url,File file,int startPosition,int endPosition){
		this.url=url;
		this.file=file;
		this.startPosition=startPosition;
		this.curPosition=startPosition;
		this.endPosition=endPosition;
	}
	@Override
	public void run() {
        BufferedInputStream bis = null;
        RandomAccessFile fos = null;                                               
        byte[] buf = new byte[BUFFER_SIZE];
        URLConnection con = null;
        try {
            con = url.openConnection();
            con.setAllowUserInteraction(true);
            //设置当前线程下载的起点,终点
            con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
            //使用java中的RandomAccessFile 对文件进行随机读写操作
            fos = new RandomAccessFile(file, "rw");
            //设置开始写文件的位置
            fos.seek(startPosition);
            bis = new BufferedInputStream(con.getInputStream());  
            //开始循环以流的形式读写文件
            while (curPosition < endPosition) {
                int len = bis.read(buf, 0, BUFFER_SIZE);                
                if (len == -1) {
                    break;
                }
                fos.write(buf, 0, len);
                curPosition = curPosition + len;
                if (curPosition > endPosition) {
                	downloadSize+=len - (curPosition - endPosition) + 1;
                } else {
                	downloadSize+=len;
                }
            }
            //下载完成设为true
            this.finished = true;
            bis.close();
            fos.close();
        } catch (IOException e) {
          Log.d(getName() +" Error:", e.getMessage());
        }
	}
 
	public boolean isFinished(){
		return finished;
	}
 
	public int getDownloadSize() {
		return downloadSize;
	}
}

 

接下来就是使用图形界面来获取需要下载的内容,并实时更新下载进度条,代码如下所示:

 

package com.ideasandroid.demo;
 
import java.io.File;
import java.net.URL;
import java.net.URLConnection;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
 *  Copyright (C) 2010 ideasandroid
 *  演示android多线程下载
 *  欢迎访问http://www.ideasandroid.com
 *  让程序开发不再那么神秘
 */
public class FileDownloadDemo extends Activity {
 
	private EditText downloadUrl;
	private EditText downloadFileName;
	private EditText downloadThreadNum;
	private Button downloadBt;
	private ProgressBar downloadProgressBar;
	private TextView progressMessage;
	private int downloadedSize = 0;
	private int fileSize = 0;
 
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
 
		downloadUrl = (EditText) findViewById(R.id.downloadUrl);
		downloadFileName = (EditText) findViewById(R.id.downloadFileName);
		downloadThreadNum = (EditText) findViewById(R.id.downloadThreadNum);
		progressMessage = (TextView) findViewById(R.id.progressMessage);
		downloadBt = (Button) findViewById(R.id.downloadBt);
		downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);
		downloadProgressBar.setVisibility(View.VISIBLE);
		downloadProgressBar.setMax(100);
		downloadProgressBar.setProgress(0);
		downloadBt.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				download();
			}
		});
	}
 
	private void download() {
		// 获取SD卡目录
		String dowloadDir = Environment.getExternalStorageDirectory()
				+ "/ideasdownload/";
		File file = new File(dowloadDir);
		//创建下载目录
		if (!file.exists()) {
			file.mkdirs();
		}
 
		//读取下载线程数,如果为空,则单线程下载
		int downloadTN = Integer.valueOf("".equals(downloadThreadNum.getText()
				.toString()) ? "1" : downloadThreadNum.getText().toString());
		//如果下载文件名为空则获取Url尾为文件名
		int fileNameStart = downloadUrl.getText().toString().lastIndexOf("/");
		String fileName = "".equals(downloadFileName.getText().toString()) ? downloadUrl
				.getText().toString().substring(fileNameStart)
				: downloadFileName.getText().toString();
		//开始下载前把下载按钮设置为不可用
		downloadBt.setClickable(false);
		//进度条设为0
		downloadProgressBar.setProgress(0);
		//启动文件下载线程
		new downloadTask(downloadUrl.getText().toString(), Integer
				.valueOf(downloadTN), dowloadDir + fileName).start();
	}
 
	Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			//当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息
			int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();
			if (progress == 100) {
				downloadBt.setClickable(true);
				progressMessage.setText("下载完成!");
			} else {
				progressMessage.setText("当前进度:" + progress + "%");
			}
			downloadProgressBar.setProgress(progress);
		}
 
	};
 
	/**
	 * @author ideasandroid
	 * 主下载线程
	 */
	public class downloadTask extends Thread {
		private int blockSize, downloadSizeMore;
		private int threadNum = 5;
		String urlStr, threadNo, fileName;
 
		public downloadTask(String urlStr, int threadNum, String fileName) {
			this.urlStr = urlStr;
			this.threadNum = threadNum;
			this.fileName = fileName;
		}
 
		@Override
		public void run() {
			FileDownloadThread[] fds = new FileDownloadThread[threadNum];
			try {
				URL url = new URL(urlStr);
				URLConnection conn = url.openConnection();
				//获取下载文件的总大小
				fileSize = conn.getContentLength();
				//计算每个线程要下载的数据量
				blockSize = fileSize / threadNum;
				// 解决整除后百分比计算误差
				downloadSizeMore = (fileSize % threadNum);
				File file = new File(fileName);
				for (int i = 0; i < threadNum; i++) {
					//启动线程,分别下载自己需要下载的部分
					FileDownloadThread fdt = new FileDownloadThread(url, file,
							i * blockSize, (i + 1) * blockSize - 1);
					fdt.setName("Thread" + i);
					fdt.start();
					fds[i] = fdt;
				}
				boolean finished = false;
				while (!finished) {
					// 先把整除的余数搞定
					downloadedSize = downloadSizeMore;
					finished = true;
					for (int i = 0; i < fds.length; i++) {
						downloadedSize += fds[i].getDownloadSize();
						if (!fds[i].isFinished()) {
							finished = false;
						}
					}
					//通知handler去更新视图组件
					handler.sendEmptyMessage(0);
					//休息1秒后再读取下载进度
					sleep(1000);
				}
			} catch (Exception e) {
 
			}
 
		}
	}
}

 

 

 

分享到:
评论

相关推荐

    Android多线程处理 详解

    Android多线程处理 详解,比较详细的分析了Android的多线程机理

    12_Android 多线程AsyncTask详解

    12_Android 多线程AsyncTask详解

    Android多线程详解与Demo

    一些在Android上巧妙使用多线程的方法与经验,希望对大家有所帮助

    Android多线程详解.pdf

    Android多线程详解.pdf

    android客户端多线程下载案例(实现断点续传,包括客户端服务端,还有注释)

    android客户端多线程下载,断点续传,多线程下载,网络编程详解代码 网络搜索《Android 4.0 网络编程详解代码》中的 第5章:Android中的网络数据下载及JSON的操作 中代码不全,少了个终于的activity,现自己跑通后上传以...

    Android多线程下载示例详解

    主要为大家详细介绍了Android多线程下载示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    Android多线程断点续传下载示例详解

    在上一篇博文《Android多线程下载示例》中,我们讲解了如何实现Android的多线程下载功能,通过将整个文件分成多个数据块,开启多个线程,让每个线程分别下载一个相应的数据块来实现多线程下载的功能。多线程下载中,...

    Android AsyncTask多线程详解

    Android Asynctask 先小试牛刀,了解一下各个方法执行过程,关注博客http://himici.com/

    android多线程handler/message机制详解

    主要对handler 、message机制进行了详解,如果想了解更多android相关知识,可以去我博客看看

    Handler与Android多线程详解

    下面是一段大家都比较熟悉的代码: 代码如下:Handler ...上述代码中的handler并没有调用线程myThread的start()方法,而是直接调用了run()方法,这也就意味着实际上并没有创建一个新的线程,只是在当前线程中调用run()

    Android多线程学习实例详解

    主要介绍了Android多线程,结合实例形式较为详细的分析了Android多线程的概念、使用方法与相关注意事项,需要的朋友可以参考下

    Android多线程AsyncTask详解

    本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信。 一、android当中的多线程 在Android当中,当一个应用程序的组件启动的时候,并且没有其他的应用程序组件在运行时,...

    详解Android使用OKHttp3实现下载(断点续传、显示进度)

    我们会用到OKHttp3来做网络请求,使用RxJava来实现线程的切换,并且开启Java8来启用Lambda表达式,毕竟RxJava实现线程切换非常方便,而且数据流的形式也非常舒服,同时Lambda和RxJava配合食用味道更佳 打开我们的app ...

    详解Android中的多线程断点下载

    本文主要介绍了Android中多线程下载的几个步骤以及实现功能的具体代码,具有很好的参考价值,需要的朋友一起来看下吧

    Android 多线程的实现方法总结

    Android 多线程的实例详解 Java多线程方式 1. 继承Thread线程,实现run方法 2. 实现Runnable接口 JAVA单继承性,当我们想将一个已经继承了其他类的子类放到Thread...Android多线程方式 主要集中在UI线程和其他线

    Android 多线程处理之多线程详解

    handler.post(r)其实这样并不会新起线程,只是执行的runnable里的run()方法,却没有执行start()方法,所以runnable走的还是UI线程。 1.如果像这样,是可以操作ui,但是run还是走在主线程,见打印出来的Log线程名字是...

    Android Handler多线程详解

    Android–多线程之Handler 前言  Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不 允许Activity新启动的线程访问该Activity里的UI组件,...

Global site tag (gtag.js) - Google Analytics