一:使用多线程实现下载

private EditText etpath;//服务地址
private LinearLayout ll ;
// 访问服务器
String path ;
// 设定线程的数量
int threadcount = 3;
//定义正在执行的线程数量
int runningThreadcount = threadcount ;
//建一个集合存放进度条
List<ProgressBar> list = new ArrayList<ProgressBar>() ;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etpath = (EditText) findViewById(R.id.etpath);
ll = (LinearLayout) findViewById(R.id.ll) ;

//加载进度条控件
for (int i = 0; i < threadcount; i++) {
ProgressBar pb = (ProgressBar)View.inflate(this, R.layout.pb, null) ;
}
}

public void download(View view){

//将进度条加入到线性组件中显示出来

for(int i = 0; i < threadcount; i++){

ll.addView(list.get(i));}

new Thread() {
public void run() {

path = etpath.getText().toString().trim();

if (TextUtils.isEmpty(path)) {
runOnUiThread(new Runnable() {

@Override
public void run() {
Toast.makeText(MainActivity.this, "路径不能为空", 0)
.show();
}
});
return;
}
// 下载文件
try {
// 创建连接服务器对象
URL url = new URL(path);
HttpURLConnection http = (HttpURLConnection) url
.openConnection();
// 设定连接参数
http.setRequestMethod("GET");
// 设定连接的超时时间
http.setConnectTimeout(5000);
// 获取返回的状态吗
int code = http.getResponseCode();
if (code == 200) {
// 获得返回的文件的大小
int length = http.getContentLength();
// 2.创建一个文件和下载的文件大小一样
RandomAccessFile raf = new RandomAccessFile(
getFileName(path), "rw");
// 设置文件的大小
raf.setLength(length);
// 3.启动多个线程下载文件
for (int id = 0; id < threadcount; id++) {
// 计算每个线程要下载的区块大小
int blocksize = length / threadcount;
// 计算每个线程下载的开始和结束位置
int startIndex = id * blocksize;
int endIndex = (id + 1) * blocksize - 1;
// 特殊情况:最后一个线程需要承担更多的数据
if (id == threadcount - 1) {
endIndex = length - 1;
}
// 启动线程下载数据
DownLoadThread dlt = new DownLoadThread(path, id,
startIndex, endIndex);
dlt.start();
}
}
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(new Runnable() {

@Override
public void run() {
Toast.makeText(MainActivity.this, "网络连接错误", 0).show() ;
}
}) ;
}
};
}.start();

}

//专门下载的类

// 专门下载的类
public class DownLoadThread extends Thread {
private String path;
private int id;
private int startIndex;
private int endIndex;

public DownLoadThread(String path, int id, int startIndex, int endIndex) {
this.path = path;
this.id = id;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
@Override
public void run() {
//设置进度条
ProgressBar pb = list.get(id) ;
int total = 0;// 记录每个线程已经下载了多少字节
try {
URL url = new URL(path);
HttpURLConnection http = (HttpURLConnection) url
.openConnection();
http.setRequestMethod("GET");
http.setConnectTimeout(5000);
// 读取相应的文件,判断文件是否存在,存在的话,应读取里面的数据
//拿到sd卡的文件an存储路径
String cunPath = Environment.getExternalStorageDirectory().getAbsolutePath() ;
File file = new File(cunPath + "/" + id + ".txt");
if (file.exists() && file.length() > 0) {
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(
new InputStreamReader(fis));
total = Integer.parseInt(br.readLine());
br.close();
// 改变线程下载的起始位置
startIndex = startIndex + total;
System.out.println("线程" + id + "下载的真实范围:" + startIndex
+ "~" + endIndex);
}
//设置最大值
pb.setMax(endIndex-startIndex) ;

// 注意,一定要设置一个请求头(范围),指定此线程要下载的数据的范围
http.setRequestProperty("Range", "bytes=" + startIndex + "-"
+ endIndex);

int code = http.getResponseCode();
// 200代表的是服务器把数据向客户端传输完毕,206代表的是服务端传输局部数据完毕
System.out.println("code =" + code);
if (code == 206) {

InputStream is = http.getInputStream();
// 拿到已经在硬盘上的对应的文件
RandomAccessFile raf = new RandomAccessFile(
getFileName(path), "rw");
// 将文件的指针移动到开始写入的位置
raf.seek(startIndex);
// 将流中的数据写入到文件中

byte[] bs = new byte[1024];
int b = 0;

while ((b = is.read(bs)) != -1) {
raf.write(bs, 0, b);

total += b;

// 真正同步写入到底层的存储设备上
RandomAccessFile f = new RandomAccessFile(cunPath + "/" + id + ".txt",
"rws");
f.write((total + "").getBytes());
f.close();

//改变进度条的当前位置
pb.setProgress(total) ;
}

raf.close();
is.close();

System.out.println("线程" + id + "下载完毕");
System.out.println("线程" + id + "下载的范围是:" + startIndex
+ " ~" + endIndex);

runningThreadcount-- ;
System.out.println(runningThreadcount);
if(runningThreadcount == 0){
//所有的线程都下载完毕了
runOnUiThread(new Runnable() {

@Override
public void run() {
Toast.makeText(MainActivity.this, "文件下载成功", 0).show() ;
}
}) ;
}
// 将对应的临时文件删除
File tempFile = new File(cunPath + "/" + id + ".txt");
if (tempFile.exists())
tempFile.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

/**
* 通过用户传递的路径拿到文件名
*
* @param path
* @return
*/
public static String getFileName(String path) {
String externalPath = Environment.getExternalStorageDirectory().getAbsolutePath() ;
return externalPath + "/" +path.substring(path.lastIndexOf("/") + 1);
}

更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  4. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  5. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  6. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  7. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  8. android sqlite 不存在插入,存在更新语句
  9. Spring For Android初体验

随机推荐

  1. Android Vibrator手机振动 API详解
  2. Android 学习笔记--android――Activity
  3. Android jni中数组参数的传递方式
  4. mk文件中配置lib arm64 文件夹
  5. Android DataBinding介绍
  6. Android - 绘画出圆并保存为图片(详)
  7. Android com.android.internal.R 添加新i
  8. uni-app 跳转Android原生界面(Activity),
  9. Android 文件操作,删除,拷贝文件等
  10. Android Interface Definition Language