多线程下载:
目的:最大限度的利用CPU资源
过程:
1.获得下载文件的长度,然后设置本地文件长度
2.根据文件长度和线程数计算每条线程下载的数据长度和下载位置
3.使用HTTP的range字段指定每条线程从什么位置下载,到什么位置停止
4.保存文件。使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
首先先看一下依赖
compile 'com.youth.banner:banner:1.4.9'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.jcodecraeer:xrecyclerview:1.3.2'
compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.okhttp3:okhttp:3.1.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
用MVP模式首先看View层
接口类
public interface IDialogView {
public void showDialog();
}
再看MODEL层
接口类
public interface IDownLoadModel {
public IDataView downLoad();
}
public class DownLoadModel implements IDownLoadModel {
@Override
public IDataView downLoad() {
Retrofit retrofit=new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://10.0.2.2:8080/")
.build();
IDataView dataView = retrofit.create(IDataView.class);
return dataView;
}
}
PRESENTER层
public abstract class BaseActivity<T extends IDataPresenter> extends AppCompatActivity {
public T presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createPresenter();
}
public abstract void createPresenter();
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter!=null){
presenter.detach();
}
}
}
public interface IDataPresenter<T> {
public void attach(T view);
public void detach();
}
public class DownLoadPresenter implements IDataPresenter<IDialogView> {
DownLoadModel model;
SoftReference<IDialogView> softView;
public DownLoadPresenter(IDialogView view) {
attach(view);
model = new DownLoadModel();
}
public void getDataLength(final String downLoadUrl, final String path, final long threadNum) {
model.downLoad().getFileLength(downLoadUrl)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Observer<ResponseBody>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(ResponseBody responseBody) {
long length = responseBody.contentLength();
DownLoadTask.getDownLoadData(DownLoadPresenter.this, downLoadUrl, path, length, threadNum);
}
});
}
public void getDownLoadFile(String downLoadUrl, String range, final File file, final long startPosition) {
model.downLoad().downLoadFile(downLoadUrl, range)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Observer<ResponseBody>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(ResponseBody responseBody) {
// Log.i("+++++++++++++++++", "onResponse: "+response.body().contentLength());
BufferedInputStream bis = new BufferedInputStream(responseBody.byteStream());
try {
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.seek(startPosition);
byte[] buff = new byte[1024 * 8];
int len = 0;
while ((len = bis.read(buff)) != -1) {
raf.write(buff, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
public void attach(IDialogView view) {
softView = new SoftReference<IDialogView>(view);
}
@Override
public void detach() {
softView.clear();
}
}
public interface IDataView {
@Streaming
@POST("{fileName}")
Observable<ResponseBody> getFileLength(@Path("fileName") String fileName);
@Streaming
@POST("{fileName}")
Observable<ResponseBody> downLoadFile(@Path("fileName") String fileName, @Header("Range") String range);
}
public class DownLoadThread{
private String downLoadUrl;
private String path;
private long threadNum;
private DownLoadPresenter presenter;
public DownLoadThread(String downLoadUrl, String path, long threadNum,DownLoadPresenter presenter) {
this.downLoadUrl = downLoadUrl;
this.path = path;
this.threadNum = threadNum;
this.presenter=presenter;
}
public void show(){
presenter.getDataLength(downLoadUrl,path,threadNum);
}
}
public class DownLoadFileThread extends Thread {
DownLoadPresenter presenter;
private String downLoadUrl;
private String range;
private File file;
private long startPosition;
public DownLoadFileThread(DownLoadPresenter presenter, String downLoadUrl, String range, File file, long startPosition) {
this.presenter = presenter;
this.downLoadUrl = downLoadUrl;
this.range = range;
this.file = file;
this.startPosition = startPosition;
}
@Override
public void run() {
presenter.getDownLoadFile(downLoadUrl,range,file,startPosition);
}
}
public class DownLoadTask {
public static void getDownLoadData(DownLoadPresenter presenter,String downLoadUrl, String path, long length, long threadNum){
File file=new File(path);
if (!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
long blockSize=length/threadNum;
for (int i = 0; i < threadNum; i++) {
long startPosition=blockSize*i;
if (i==threadNum-1){
blockSize=length-blockSize*(threadNum-1);
Log.i("+++++++++++", "getDownLoadData: "+blockSize);
}
String range = "bytes=" + startPosition + "-" + (startPosition + blockSize - 1);
Log.i("++++++++++++++", "downLoadTask: "+startPosition+"-----"+(startPosition+blockSize-1));
new DownLoadFileThread(presenter,downLoadUrl,range,file,startPosition).start();
}
}
}
public class MainActivity extends BaseActivity<DownLoadPresenter> implements IDialogView {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData() {
showDialog();
Log.i("---------", "initData: "+presenter);
}
@Override
public void createPresenter() {
presenter=new DownLoadPresenter(this);
}
@Override
public void showDialog() {
Log.i("==============", "initData: "+presenter);
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setTitle("是否更新")
.setMessage("你太low了,赶快更新")
.setNegativeButton("取消",null)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
new DownLoadThread("QQ.apk",getCacheDir()+"/qq.apk",5,presenter).show();
}
}).show();
}
}