这个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>