您的位置:首页 > 其它

安卓基础:实现多线程下载本次服务器的图片

2016-03-16 14:25 204 查看
实现原理

(1)首先获得下载文件的长度,然后设置本地文件的长度。

(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。

如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示:



(网上找的图)

例如10M大小,使用3个线程来下载,

线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M

下载开始位置:线程id*每条线程下载的数据长度 = ?

下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

直接上代码:

1.DownLoad.java

import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import java.io.File;
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.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class DownLoad {

private Handler handler;

public DownLoad(Handler handler) {
this.handler = handler;
}

//创建是哪个线程池,用来下载数据
private Executor threadPool = Executors.newFixedThreadPool(3);

//给线程池创建一个Runnable对象
static class DownLoadRunnable implements Runnable{

private String url;
private String fileName;
private long start;//下载的启示位置
private long end;//下载的结束位置
private Handler handler;

public DownLoadRunnable(String url, String fileName, long start, long end, Handler handler) {
this.url = url;
this.fileName = fileName;
this.start = start;
this.end = end;
this.handler = handler;
}

@Override
public void run() {
try {
URL httpUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
/*
1.Http协议字段 Range "bytes="+start+"-"+end
2.RandomAccessFile设置写入的位置
3.开启线程发送网路请求
*/
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);//获得请求数据的长度;
//通过RandomAccessFile(随机读取流)对本地文件进行写操作,rwd代表可读可写可执行
RandomAccessFile access = new RandomAccessFile(new File(fileName),"rwd");
access.seek(start);//从start开始写
InputStream in = conn.getInputStream();
byte[] b = new byte[1024*4];//创建一个缓冲区,4K
int len = 0;
while((len = in.read(b))!=-1){
access.write(b,0,len);//从0开始,读取len的一个长度
}
//读取完之后关闭这个流
if(access!=null){
access.close();
}
//读取玩之后关闭输入流
if(in!=null){
in.close();
}
//所有文件下载完成之后,给主线程发送一个消息
Message message = new Message();
message.what = 1;
handler.sendMessage(message);

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* 多线程文件下载
*/
public void downLoadFile(String url){
try {
URL httpUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
//拿到用来下载图片的长度
int count = conn.getContentLength();
//将长度分为三段
int block = count/3;

//指定一个文件的名字
String fileName = getFileName(url);
//拿到文件名后,需要指定一个文件的下载地址,下载到SD卡
File parent = Environment.getExternalStorageDirectory();
File fileDownLoad = new File(parent,fileName);

//往线程池提交任务
/**
* 假如有11个字节,则11/3 = 3
* 第一个线程 0-2
* 第二个线程 3-5
* 第三个线程 6-10  最后一个线程处理多出来的
*/
for (int i = 0; i<3;i++){
long start = i*block;
long end = (i+1)*block-1;
if(i==2){
end = count;
}
//fileDownLoad.getAbsolutePath()是获取绝对路径
DownLoadRunnable runnable = new DownLoadRunnable(url,
fileDownLoad.getAbsolutePath(),start,end,handler);
//通过线程池去提交任务
threadPool.execute(runnable);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//取出url后缀名的方法
public String getFileName(String url){
return url.substring(url.lastIndexOf("/")+1);
}

}


2.MainActivity.java

package com.ceshi.hwy.download;

import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

private Button button;
private TextView textView;

private int count = 0;

/**
* 使用Handler更新UI界面信息
*/
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
int result = msg.what;
count+=result;
if(count == 3){
textView.setText("download success!!!");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
textView = (TextView) findViewById(R.id.textview);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(){
@Override
public void run() {
DownLoad downLoad = new DownLoad(handler);
downLoad.downLoadFile("http://192.168.173.1:8080/web/hai.jpg");
}
}.start();

}
});
}
}


3.布局文件就一个按钮和一个TextView,下面是结果图



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: