您的位置:首页 > 其它

安卓开发-多线程常规实现+xUtils-master开源框架实现 断点下载

2017-09-17 14:38 477 查看
《方式一:多线程下载之常规实现》

原理如图:



1.创建url

URL url = new URL(getUrl());

//下载来自tomcat下的webapps/ROOT/resource.rar文件,10.0.2.2是安卓映射的服务器的地址,此时不再是localhost或者是本机ip
private String getUrl(){
return "http://10.0.2.2:8080/resource.rar";
}


2.打开链接

HttpURLConnection conn = (HttpURLConnection) url.openConnection();


3.判断相应码是否为200(没有设置请求头为200)

if(conn.getResponseCode() == 200){


4.得到要下载资源的长度(4.5.6.7在if中)

int contentLength = conn.getContentLength();


5.利用RandomAccessFile在files文件中创建和将要下载文件一样容量的空文件

File file = new File(getFilesDir(), getFileName(getUrl()));
//设置文件权限为可读可写
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(contentLength);//定义空文件长度


6.计算出每个线程负责下载文件的大小

//MAX_THREAD_NUM为全局变量,设定资源分给几个线程下载
int preThreadLength = contentLength/MAX_THREAD_NUM;


7.对每个线程的任务做迭代下载

for (int i = 0; i < MAX_THREAD_NUM; i++) {
int startIndex = i * preThreadLength;//线程下载的起始点
int endIndex = (i + 1) * preThreadLength - 1;//线程下载的结束点
if(i == MAX_THREAD_NUM - 1){
endIndex = contentLength - 1;
}
//每次从新开启一个新的线程下载,i可用来判断是否下载完毕
new DownLoadFile(i, startIndex, endIndex).start();
}


8.创建下载资源线程类:

8.1.创建全局变量:


private int mCurrentThreadNum;//当前线程号(默认从0开始)
private int mStartIndex;//当前线程下载的起始点
private int mEndIndex;//当前线程下载的结束点
private int mLastIndex;//上次下载断点位置


8.2.创建构造器:


public DownLoadFile(int currentThreadNum, int firstIndex, int endIndex){
mCurrentThreadNum = currentThreadNum;
mStartIndex = firstIndex;
mEndIndex = endIndex;
mLastIndex = firstIndex;
}


8.3:重写Thread中的run方法:


public void run() {
try {
//1.创建url
URL url = new URL(getUrl());
//2.打开链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

//3.得到files中的断点文件信息,并将值赋给mLastIndex
File file = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()));
if(file.exists()){
InputStream is = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
mLastIndex = Integer.valueOf(reader.readLine());
}

//4.设置请求头信息,如果是第一次,就用mStartIndex(下载相关:Range  :  bytes=起始点-结束点)
conn.setRequestProperty("Range", "bytes=" +( mLastIndex != 0 ? mLastIndex : mStartIndex )+ "-" + mEndIndex);
//5.判断相应码是否为206,设置下载的请求头后响应码不再是200
if(conn.getResponseCode() == 206){
//6.获取输入流
InputStream is = conn.getInputStream();

//7.利用RandomAccessFile得到在file下创建好的文件
File files = new File(getFilesDir(), getFileName(getUrl()));
RandomAccessFile raf = new RandomAccessFile(files, "rw");
raf.skipBytes(mLastIndex);//跳过多少个字节

//8.向文件中写数据
byte[] buffer = new byte[1024];
int readCount;
while((readCount = is.read(buffer)) != -1){
mLastIndex += readCount;
raf.write(buffer, 0, readCount);

//9.根据当前线程数和下载的资源名创建断点位置信息文件,并把数据写入
File recordFile = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()) );
RandomAccessFile recordRaf = new RandomAccessFile(recordFile, "rws");
recordRaf.write((mLastIndex + "").getBytes());

//10,为进度条设置max和Progress值
SeekBar sb = (SeekBar) mPbContainerLl.getChildAt(mCurrentThreadNum);
sb.setMax(mEndIndex - mStartIndex);
sb.setProgress(mLastIndex);
}
//11.下载完成后将断点位置文件删除
for (int i = 0; i < MAX_THREAD_NUM; i++) {
getRecoredFile(mCurrentThreadNum, getFileName(getUrl())).delete();
}

//12.下载完成的提示
if(mCurrentThreadNum == MAX_THREAD_NUM - 1){
Log.v("520it", "下載完成");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "下載完成!", Toast.LENGTH_SHORT).show();
}
});

}
}
} catch (Exception e) {
e.printStackTrace();
}
}

//根据当前线程数和下载的资源名创建断点位置信息文件
private File getRecoredFile(int currentThreadNum,
String fileName) {
String recordFileName = fileName.substring(0, fileName.lastIndexOf(".")) + "#" + currentThreadNum + ".txt";
return new File(getFilesDir(),recordFileName);
}


9.完整代码:

package com.m520it.downloadofmultithreadpoint;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.Toast;

public class MainActivity extends Activity {
private int MAX_THREAD_NUM = 3;
private LinearLayout mPbContainerLl;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mPbContainerLl = (LinearLayout) findViewById(R.id.pbContainer_ll);

}

public void downLoadOnClick(View v){
for (int i = 0; i < MAX_THREAD_NUM; i++) {
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.pbcontainer_layout, null);
mPbContainerLl.addView(view.findViewById(R.id.pb));
}

new Thread(){
public void run() {
try {
//1.创建url
URL url = new URL(getUrl());
//2.打开链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//3.判断相应码是否为200(没有设置请求头为200)
if(conn.getResponseCode() == 200){
//4.得到文件的长度
int contentLength = conn.getContentLength();
//5.利用RandomAccessFile在files文件中创建和将要下载文件一样容量的空文件
File file = new File(getFilesDir(), getFileName(getUrl()));
RandomAccessFile raf = new RandomAccessFile(file, "rw");//设置文件权限为可读可写
raf.setLength(contentLength);//定义空文件长度
//6.计算出每个线程负责下载文件的大小
int preThreadLength = contentLength/MAX_THREAD_NUM;
//7.对每个线程的任务做迭代下载
for (int i = 0; i < MAX_THREAD_NUM; i++) {
int startIndex = i * preThreadLength;//线程下载的起始点
int endIndex = (i + 1) * preThreadLength - 1;//线程下载的结束点,最后一个线程负责下载其他线程剩下的所有任务
if(i == MAX_THREAD_NUM - 1){
endIndex = contentLength - 1;
}
Log.v("520it", "startup=" + startIndex + " endIndex=" + endIndex);
new DownLoadFile(i, startIndex, endIndex).start();//每次从新开启一个新的线程下载,i可用来判断是否下载完毕
}
}

} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}

class DownLoadFile extends Thread{
private int mCurrentThreadNum;//当前线程号(默认从0开始) private int mStartIndex;//当前线程下载的起始点 private int mEndIndex;//当前线程下载的结束点 private int mLastIndex;//上次下载断点位置

public DownLoadFile(int currentThreadNum, int firstIndex, int endIndex){ mCurrentThreadNum = currentThreadNum; mStartIndex = firstIndex; mEndIndex = endIndex; mLastIndex = firstIndex; }

public void run() {
try {
//1.创建url
URL url = new URL(getUrl());
//2.打开链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

//3.得到files中的断点文件信息,并将值赋给mLastIndex
File file = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()));
if(file.exists()){
InputStream is = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
mLastIndex = Integer.valueOf(reader.readLine());
}

//4.设置请求头信息,如果是第一次,就用mStartIndex(下载相关:Range : bytes=起始点-结束点)
conn.setRequestProperty("Range", "bytes=" +( mLastIndex != 0 ? mLastIndex : mStartIndex )+ "-" + mEndIndex);
//5.判断相应码是否为206,设置下载的请求头后响应码不再是200
if(conn.getResponseCode() == 206){
//6.获取输入流
InputStream is = conn.getInputStream();

//7.利用RandomAccessFile得到在file下创建好的文件
File files = new File(getFilesDir(), getFileName(getUrl()));
RandomAccessFile raf = new RandomAccessFile(files, "rw");
raf.skipBytes(mLastIndex);//跳过多少个字节

//8.向文件中写数据
byte[] buffer = new byte[1024];
int readCount;
while((readCount = is.read(buffer)) != -1){
mLastIndex += readCount;
raf.write(buffer, 0, readCount);

//9.根据当前线程数和下载的资源名创建断点位置信息文件,并把
File recordFile = getRecoredFile(mCurrentThreadNum, getFileName(getUrl()) );
RandomAccessFile recordRaf = new RandomAccessFile(recordFile, "rws");
recordRaf.write((mLastIndex + "").getBytes());

//为进度条设置max和Progress值
SeekBar sb = (SeekBar) mPbContainerLl.getChildAt(mCurrentThreadNum);
sb.setMax(mEndIndex - mStartIndex);
sb.setProgress(mLastIndex);
}
//下载完成后将断点位置文件删除
for (int i = 0; i < MAX_THREAD_NUM; i++) {
getRecoredFile(mCurrentThreadNum, getFileName(getUrl())).delete();
}

//下载完成的提示
if(mCurrentThreadNum == MAX_THREAD_NUM - 1){
Log.v("520it", "下載完成");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "下載完成!", Toast.LENGTH_SHORT).show();
}
});

}

}
} catch (Exception e) {
e.printStackTrace();
}
}

private File getRecoredFile(int currentThreadNum,
String fileName) {
String recordFileName = fileName.substring(0, fileName.lastIndexOf(".")) + "#" + currentThreadNum + ".txt";
return new File(getFilesDir(),recordFileName);
}

}

private String getFileName(String url){
return url.substring(url.lastIndexOf("/") + 1);
}

private String getUrl(){
return "http://10.0.2.2:8080/resource.rar";
}

}


10.RandomAccessFile的功能总结:

10.1:在指定位置创建一个指定大小的空文件:


File file = new File(getFilesDir(), getFileName(getUrl()));
//设置文件权限为可读可写
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(contentLength);//定义空文件长度


10.2:可在指定文件内跳过指定个数的字节进行写入数据


File files = new File(getFilesDir(), getFileName(getUrl()));
RandomAccessFile raf = new RandomAccessFile(files, "rw");
raf.skipBytes(mLastIndex);//跳过多少个字节

raf.write(buffer, 0, readCount);


《方式二:xUtils-master开源框架实现断点下载》

1.引入框架,如图:



2.创建一个下载按钮,为其设置下载点击事件:

public void downLoadClick(View v){
//1.创建httpUtils对象
HttpUtils httpUtils = new HttpUtils();

//创建资源文件保存位置文件
File file = new File(getFilesDir(), getFileName(getUrl()));
//2.调用下载函数(资源路径,保存资源位置的绝对路径,是否支持断点下载,请求回调函数重写)
httpUtils.download(getUrl(), file.getAbsolutePath(), true, new RequestCallBack<File>()
{
@Override
public void onSuccess(ResponseInfo<File> responseInfo) {
Toast.makeText(MainActivity.this, "下載完成", Toast.LENGTH_SHORT).show();
Log.v("520it", "下載完成");
}
@Override
public void onFailure(HttpException error, String msg) {
// TODO Auto-generated method stub
}

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