这个okhttp的话直接用原生的就可以了
public class MainActivity extends AppCompatActivity {
//要下载的文件地址
private String url="https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk";
//设置线程数量 线程运行时的长度
private int counter=3,runningThreadCount=0,blockSize;
private ProgressBar bar1,bar2,bar3;
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 0:
bar1.setProgress(msg.arg1);
break;
case 1:
bar2.setProgress(msg.arg1);
break;
case 2:
bar3.setProgress(msg.arg1);
break;
}
}
};
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bar1=findViewById(R.id.bar1);
bar2=findViewById(R.id.bar2);
bar3=findViewById(R.id.bar3);
}
public void cc(View view) {
OKhttptils.Post(url, new HashMap<String, String>(), new HttpCallBack() {
@Override
public void success(String response, long Length) {
Log.d("aaaaaa", "success: "+Length);
Log.d("aaaaaa", "success: "+response);
try {
Log.d("aaaaaa", ": "+getExternalCacheDir().toString());
//创建一个空的文件夹并且设置文件长度大小等于地址上的文件大小
RandomAccessFile randomAccessFile = new RandomAccessFile(getExternalCacheDir() + getDownloadFileName(url),"rw");
//给空文件设置大小
randomAccessFile.setLength(Length);
//关闭文件读取流
randomAccessFile.close();
//每一个线程分配的下载长度
blockSize= (int) Length / counter;
bar1.setMax(blockSize);
bar2.setMax(blockSize);
bar3.setMax(blockSize);
//分配每一个线程的下载位置
for (int i = 0; i <counter ; i++) {
int startPosition = i * blockSize;
int endPosition = (i+1) * blockSize - 1;
//如果等于最后一个的话就直接设置结束位置
if(i==(counter-1)){
endPosition = (int) Length-1;
}
Log.d("aaaaaa", ": Thread"+i+"startPosition"+startPosition+"-----endPosition"+endPosition);
//创建线程
new DownloadThread(i,startPosition,endPosition).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void fail(String response) {
}
});
}
/*
* 从网络路径获取文件名
* 网络路径 path
* 文件名 return
*
* */
private String getDownloadFileName(String path) {
return path.substring(path.lastIndexOf("/")+1);
}
/*
* 下载文件的线程
* */
private class DownloadThread extends Thread{
//线程第几个 起始位置 结束位置
private int i,startPosition,endPosition;
public DownloadThread(int i, int startPosition, int endPosition) {
this.i=i;
this.startPosition=startPosition;
this.endPosition=endPosition;
}
@Override
public void run() {
super.run();
try {
Log.d("aaaaaa", ": 4");
//创建每个线程对应的文件记录暂停下载的位置
File file = new File(getExternalCacheDir().toString(),counter + getDownloadFileName(url) + i + ".txt");
//如果这个记录文件存在的话直接读取
if(file.exists()&&file.length()>0){
FileInputStream fileInputStream = new FileInputStream(file);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
//读取上一次暂停时结尾的位置
String lastPosition = bufferedReader.readLine();
//直接把值赋值给这个线程的起始位置
startPosition = Integer.parseInt(lastPosition);
fileInputStream.close();
}else {
Log.d("aaaaaa", ": Thread"+i+"startPosition"+startPosition+"-----endPosition"+endPosition);
Request request = new Request.Builder()
//确定下载的范围,添加此头,则服务器就可以跳过已经下载好的部分
.addHeader("RANGE", "bytes=" + startPosition + "-" + endPosition)
.url(url)
.build();
Call call = new OkHttpClient.Builder().build().newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("aaaaaa", ": "+e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//得到下载文件输入流
InputStream inputStream = response.body().byteStream();
//如果有这个文件就打开 没有则创建
RandomAccessFile rw = new RandomAccessFile(getExternalCacheDir() + getDownloadFileName(url), "rw");
//
rw.seek(startPosition);
//缓存区 读取文件并且写入文件
byte[] buffer = new byte[1024];
int len = -1;
//统计下载长度位置
int total = 0;
while ((len = inputStream.read(buffer)) != -1){
rw.write(buffer,0,len);
total += len;
RandomAccessFile randomAccessFile = new RandomAccessFile(getExternalCacheDir().toString()+counter + getDownloadFileName(url) + i + ".txt","rwd");
//保存已经下载的位置长度
randomAccessFile.write(String.valueOf(startPosition + total).getBytes());
randomAccessFile.close();
Message message = new Message();
message.what=i;
message.arg1=total;
handler.sendMessage(message);
}
inputStream.close();
rw.close();
Log.d("aaaaaa", ": Thread"+i+"下载完成");
}
});
}
} catch (Exception e) {
e.printStackTrace();
}finally {
synchronized (MainActivity.this){
runningThreadCount--;
if(runningThreadCount<=0){
Log.d("aaaaaa", ": "+"下载完成");
for (int j = 0; j < counter; j++) {
File file = new File(getExternalCacheDir().toString()+ counter + getDownloadFileName(url) + i + ".txt");
Log.d("aaaaaa", ": "+file.delete());
}
}
}
}
}
}
}
2.布局
<LinearLayout
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/ed1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="线程数量"
tools:ignore="HardcodedText,TextFields" />
<EditText
android:id="@+id/ed2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="下载文件的路径"
tools:ignore="HardcodedText,TextFields" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="下载"
tools:ignore="HardcodedText"
android:onClick="cc"/>
<LinearLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="UselessLeaf">
<ProgressBar
android:id="@+id/bar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"/>
<ProgressBar
android:id="@+id/bar2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"/>
<ProgressBar
android:id="@+id/bar3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"/>
</LinearLayout>
</LinearLayout>