断点下载

2019-07-16  本文已影响0人  小慧sir
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Locale;
import java.util.concurrent.Executors;

import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.ByteString;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, MyService.class);
        startService(intent);
    }

    /**
     * OkHttp实现断点续传
     */
    public void downloadRange(View view) {
        view.setEnabled(false);
        Toast.makeText(this, "开始下载", Toast.LENGTH_SHORT).show();
        // downFromBreakPoint();
        Executors.newCachedThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    downMultipleThread();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 多线程下载
     */
    private void downMultipleThread() throws Exception {
        // 请求基本信息
        final String url = "https://alissl.ucdl.pp.uc.cn/fs08/2019/07/05/1/110_17e4089aa3a4b819b08069681a9de74b.apk";
        File directory = Environment.getExternalStorageDirectory();
        final File file = new File(directory, "a20190715.apk");
        // 通过HEAD请求获取文件大小
        final OkHttpClient client = new OkHttpClient();
        Request headRequest = new Request.Builder()
                .url(url)
                .head()
                .build();
        Call headerCall = client.newCall(headRequest);
        Response headResponse = headerCall.execute();
        long contentLength = headResponse.body().contentLength();
        System.out.println("contentLength " + contentLength);
        // 计算每个线程需要下载的范围
        int number = 3;
        long part = contentLength / number;
        for (int i = 0; i < number; i++) {
            final String key = "range" + i;
            SharedPreferences preferences = getPreferences(Context.MODE_PRIVATE);
            final long start = preferences.getLong(key, i * part);
            long end = (i + 1) * part - 1;
            if (i == (number - 1)) {
                end = contentLength;
            }
            System.out.println(start + " - " + end);
            final String range = String.format(Locale.CHINESE, "bytes=%d-%d", start, end);
            Executors.newCachedThreadPool().execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("开始:" + Thread.currentThread().getName());
                        Request request = new Request.Builder()
                                .url(url)
                                .header("range", range)
                                .get()
                                .build();
                        Call call = client.newCall(request);
                        cancelDelay(call, 2000);
                        Response response = call.execute();
                        RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
                        SharedPreferences preferences = getPreferences(Context.MODE_PRIVATE);
                        accessFile.seek(start);
                        InputStream inputStream = response.body().byteStream();
                        byte[] bytes = new byte[1024];
                        int len = inputStream.read(bytes);
                        while (len != -1) {
                            accessFile.write(bytes, 0, len);
                            preferences.edit().putLong(key, accessFile.getFilePointer()).apply();
                            len = inputStream.read(bytes);
                        }
                        System.out.println(response.body().contentLength());
                        System.out.println("结束:" + Thread.currentThread().getName());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    /**
     * 从断点处继续下载
     */
    private void downFromBreakPoint() {
        Executors.newCachedThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    downloadByOkHttp();
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println(e.getMessage());
                }
            }
        });
    }

    public void downloadByOkHttp() throws IOException {
        // 文件下载地址
        String url = "https://alissl.ucdl.pp.uc.cn/fs08/2019/07/05/1/110_17e4089aa3a4b819b08069681a9de74b.apk";
        // 创建下载文件对象
        File directory = Environment.getExternalStorageDirectory();
        File file = new File(directory, "20190715.apk");
        RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
        // 断点续传:重新开始下载的位置
        String range = String.format(Locale.CHINESE, "bytes=%d-", file.length());
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .header("range", range)
                .build();
        // 使用OkHttp请求服务器
        final Call call = client.newCall(request);
        Response response = call.execute();
        // cancelDelay(call,1000);
        // 连接服务器成功
        ResponseBody body = response.body();
        System.out.println("文件大小:" + body.contentLength());
        String header = response.header("Content-Range");
        System.out.println(header);
        // 移动文件指针到断点续传的位置
        accessFile.seek(file.length());
        // 开始断点续传
        InputStream inputStream = body.byteStream();
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        while (len != -1) {
            accessFile.write(bytes, 0, len);
            System.out.println("已下载字节:" + file.length());
            len = inputStream.read(bytes);
        }
        System.out.println("文件下载完毕:" + accessFile.getFilePointer());
    }

    public void cancelDelay(final Call call, long delayMillis) {
        Handler handler = new Handler(Looper.getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                call.cancel();
            }
        }, delayMillis);
    }
}

上一篇 下一篇

猜你喜欢

热点阅读