一、首先在本地创建一个与服务器文件大小相同的临时文件(这个很好理解,如果我想下个2G的电影,我得给先在本地占用2G的空间,不然不能下着下着没空间了是吧)。
二、计算分配几个线程去下载服务器上的资源,知道每个线程下载文件的起始位置。
那么这个起始位置怎么计算呢?
文件长度/线程个数= 每个线程下载文件的大小。那么
线程1下载的位置:0~每个线程下载文件的大小-1.
线程2:以此类推
那么就是i线程的下载起始位置: (i-1)*每个线程下载文件的大小
三、开启多个线程,每一个线程下载对应位置的文件。
四、如果所有的线程都把自己的数据下载完毕了,服务器上的资源就被下载到本地了。
五、当文件都下载到本地了,那么还有一个文件就是把各个线程下载的文件如何串起来。那么就要利用到一个
net包:网络请求,线程的处理
NetUtils
public class NetUtils {
public static void downloadFile(String downloadUrl, String path, int blockSize, int startPosition){
BufferedInputStream bis = null;
RandomAccessFile raf = null;
try {
File f = new File(path);
if(!f.exists()){
f.createNewFile();
}
URL url = new URL(downloadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(8000);
conn.setConnectTimeout(8000);
// long start = 0;
if(blockSize > 0){
// //使用线程id来计算 当前线程的开始位置和结束位置
// start = blockSize * threadId;
long end = blockSize + startPosition - 1;
//多线程下载 需要告诉服务器我要请求的是哪部分内容 需要写在请求头里面
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
Log.i(Thread.currentThread() + "======", "bytes=" + start + "-" + end);
}
int code = conn.getResponseCode();
if(code < 400){
bis = new BufferedInputStream(conn.getInputStream());
raf = new RandomAccessFile(f, "rwd");
//
raf.seek(start);
//
int len = 0;
byte[] buff = new byte[1024 * 8];
while((len = bis.read(buff)) != -1){
synchronized (NetUtils.class){
raf.write(buff, 0, len);
DialogUtils.PROGRESS += len;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(raf != null){
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static int getFileLength(String downloadUrl){
int len = 0;
try {
URL url = new URL(downloadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(8000);
conn.setConnectTimeout(8000);
len = conn.getContentLength();
} catch (Exception e) {
e.printStackTrace();
}
return len;
}
}
DownloadThread:
public class DownloadThread extends Thread{
private String downloadUrl = "";
private String path;
private int threadNum = 5;
public DownloadThread(String downloadUrl, String path) {
this.downloadUrl = downloadUrl;
this.path = path;
}
@Override
public void run() {
int len = NetUtils.getFileLength(downloadUrl);
DialogUtils.MAX_SIZE = len;
//例如 1000kb 3 333
int blockSize = len/threadNum;
// //四舍五入--- 让一个数字+0。5在四舍五入 就变成 向上取整
// int blockSize = (int) Math.round(tempSize + 0.5);
//计算出下载块以后 创建线程执行下载操作
for (int i = 0; i < threadNum; i++) {
//计算开始位置
int startPosition = blockSize * i;
//让最后一个线程下载的大小是正好的, 总长度 - 除了最后一个块的大小和
if(i == threadNum - 1){
blockSize = len - blockSize * (threadNum - 1);
}
new DownloadTask(downloadUrl, path, blockSize, startPosition).start();
}
}
public void setThreadNum(int threadNum){
this.threadNum = threadNum;
}
}
DownloadTask
public class DownloadTask extends Thread{
String downloadUrl;
String path;
int blockSize;
int startPosition;
public DownloadTask(String downloadUrl, String path, int blockSize, int startPosition) {
this.downloadUrl = downloadUrl;
this.path = path;
this.blockSize = blockSize;
this.startPosition = startPosition;
}
@Override
public void run() {
NetUtils.downloadFile(downloadUrl,path,blockSize,startPosition);
}
}
弹框的处理
public class DialogUtils {
public static long MAX_SIZE = 0;
public static long PROGRESS = -1;
public static void showUpdataDialog(final Context context){
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("是否更新")
.setMessage("太旧了,更新吧")
.setNegativeButton("就不", null)
.setPositiveButton("可以", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
new DownloadThread("http://169.254.32.59:8080/c.png", context.getCacheDir() + "/c.png").start();
showProgress(context);
}
}).show();
}
public static void showProgress(final Context context){
final ProgressDialog pd = new ProgressDialog(context);
pd.setTitle("正在更新");
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(100);
pd.show();
new AsyncTask<String, Integer, String>(){
@Override
protected String doInBackground(String... strings) {
while (PROGRESS < MAX_SIZE){
SystemClock.sleep(100);
publishProgress((int)(PROGRESS * 100 / MAX_SIZE));
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
pd.dismiss();
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
pd.setProgress(values[0]);
}
}.execute();
}
}
mainactivity:
DialogUtils.showUpdataDialog(this);