Android断点续传下载:DownloadTask类详解

这段代码是一个继承自AsyncTask的下载任务类DownloadTask,用于在后台执行具体的下载逻辑。主要包括以下几个部分:

  1. 定义了一系列的下载状态常量,包括下载成功、下载失败、暂停下载、取消下载和错误状态。
public static final int TYPE_SUCCESS = 0;//下载成功
public static final int TYPE_FAILED = 1;//下载失败
public static final int TYPE_PAUSED = 2;//暂停下载
public static final int TYPE_CANCELED = 3;//取消下载
public static final int TYPE_ERROR = 4;
  1. 定义了一系列的参数,包括DownloadListener监听器、是否取消下载和是否暂停下载的标志位、上一次的下载进度。
private DownloadListener listener;
private boolean isCanceled = false;
private boolean isPaused = false;
private int lastProgress;
  1. 在构造函数中接收DownloadListener参数,并将其赋值给listener。
public DownloadTask(DownloadListener listener){
    this.listener=listener;
}
  1. 在doInBackground方法中执行具体的下载逻辑。首先获取下载的URL地址和文件名,然后判断文件是否已存在,如果存在则获取已下载的字节数。接着使用OkHttp发送网络请求,通过断点下载的方式从指定字节开始下载文件,并实时计算下载进度并调用publishProgress方法进行通知。最后根据下载的结果返回相应的状态。
@Override
protected Integer doInBackground(String... params) {//用于在后台执行具体的下载逻辑
    InputStream is = null;
    RandomAccessFile savedFile = null;
    File file = null;

    try {
        long downloadedLength = 0; // 记录已下载的文件长度
        String downloadUrl = params[0];//从参数中获取到下载的URL地址

        //指定将文件下载到Environment.DIRECTORY_DOWNLOADS目录下,也就是SD卡的Download目录。
        String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));//根据URL地址解析出了下载的文件名。
        String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();//要下载的目录名
        file = new File(directory + fileName);
        //判断一下Download目录中是不是已经存在要下载的文件了
        if (file.exists()) {//如果已经存在的话则读取已下载的字节数,这样就可以在后面启用断点续传的功能
            downloadedLength = file.length();
        }
        //调用了getContentLength() 方法来获取待下载文件的总长度
        long contentLength = getContentLength(downloadUrl);
        if (contentLength == 0) {//如果文件长度等于0则说明文件有问题
            return TYPE_ERROR;
        } else if (contentLength == downloadedLength) {
            // 已下载字节和文件总字节相等,说明已经下载完成了
            return TYPE_SUCCESS;
        }
        //紧接着使用OkHttp来发送一条网络请求
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                // 断点下载,指定从哪个字节开始下载(已下载过的部分就不需要下载了)
                .addHeader("RANGE", "bytes=" + downloadedLength + "-")//在请求中添加了一个header,用于告诉服务器我们想要从哪个字节开始下载
                .url(downloadUrl)
                .build();
        //接下来读取服务器响应的数据。,并使用Java的文件流方式,
        // 不断从网络上读取数据,不断写入到本地,一直到文件全部下载完成为止。
        Response response = client.newCall(request).execute();
        if (response != null) {
            is = response.body().byteStream();
            savedFile = new RandomAccessFile(file, "rw");
            savedFile.seek(downloadedLength); // 跳过已下载的字节
            byte[] b = new byte[1024];
            int total = 0;
            int len;
            while ((len = is.read(b)) != -1) {
                //判断用户有没有触发暂定或者取消的操作
                if (isCanceled) {
                    return TYPE_CANCELED;//触发取消
                } else if(isPaused) {
                    return TYPE_PAUSED;//触发暂停
                } else {
                    total += len;
                    savedFile.write(b, 0, len);
                    // 计算已下载的百分比(实时计算当前的下载进度)
                    int progress = (int) ((total + downloadedLength) * 100 /
                            contentLength);
                    //调用publishProgress() 方法进行通知
                    publishProgress(progress);
                }
            }
            response.body().close();
            return TYPE_SUCCESS;
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (is != null) {
                is.close();
            }
            if (savedFile != null) {
                savedFile.close();
            }
            if (isCanceled && file != null) {
                file.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return TYPE_FAILED;

}
  1. 定义了getContentLength方法用于获取待下载文件的总长度。
private long getContentLength(String downloadUrl) throws IOException {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
            .url(downloadUrl)
            .build();
    Response response = client.newCall(request).execute();
    if (response != null && response.isSuccessful()) {
        long contentLength = response.body().contentLength();
        response.body().close();
        return contentLength;
    }
    return 0;
}
  1. 在onProgressUpdate方法中更新下载进度,通过调用DownloadListener的onProgress方法进行通知。
@Override
protected void onProgressUpdate(Integer... values) {
    int progress = values[0];//首先从参数中获取到当前的下载进度
    if (progress > lastProgress) {//和上一次的下载进度进行对比
        //如果有变化的话则调用DownloadListener的onProgress() 方法来通知下载进度更新。
        listener.onProgress(progress);
        lastProgress = progress;
    }
}
  1. 在onPostExecute方法中根据下载状态调用相应的方法进行通知。
@Override
protected void onPostExecute(Integer status) {//根据参数中传入的下载状态来进行回调
    switch (status) {//对应不同状态就调用不同的方法
        case TYPE_SUCCESS:
            listener.onSuccess();
            break;
        case TYPE_FAILED:
            listener.onFailed();
            break;
        case TYPE_PAUSED:
            listener.onPaused();
            break;
        case TYPE_CANCELED:
            listener.onCanceled();
            break;
        default:
            break;
    }
}
  1. 定义了pauseDownload和cancelDownload方法用于暂停和取消下载,通过修改isPaused和isCanceled的值来控制下载的暂停和取消。
public void pauseDownload() {
    isPaused = true;
}
public void cancelDownload() {
    isCanceled = true;
}

这段代码的实验结果是,通过DownloadTask类实现了具体的下载逻辑,并通过DownloadListener接口进行下载进度和状态的回调通知。可以根据需要进行暂停和取消下载操作。

标签: 常规


原文地址: https://gggwd.com/t/topic/L8h 著作权归作者所有。请勿转载和采集!