All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.wandersnail.common.http.download.DownloadWorker Maven / Gradle / Ivy

There is a newer version: 2.2.1
Show newest version
package cn.wandersnail.common.http.download;


import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import cn.wandersnail.common.http.TaskInfo;
import cn.wandersnail.common.http.exception.RetryWhenException;
import cn.wandersnail.common.http.util.HttpUtils;
import cn.wandersnail.common.http.util.SchedulerUtils;
import io.reactivex.disposables.Disposable;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

/**
 * date: 2019/8/23 16:17
 * author: zengfansheng
 */
public class DownloadWorker implements Disposable {
    private final Map> taskMap = new ConcurrentHashMap<>();
    private DownloadListener listener;
    private int totalTasks;
    private int successNum;
    private int failureNum;
    private boolean isCanceled;

    public DownloadWorker(T info, DownloadListener listener) {
        this.listener = listener;
        totalTasks = 1;
        info.reset();
        execute(info);
    }

    public DownloadWorker(List infos, MultiDownloadListener listener) {
        this.listener = listener;
        totalTasks = infos.size();
        for (T info : infos) {
            info.reset();
            execute(info);            
        }
    }
    
    @SuppressWarnings("unchecked")
    private void execute(T info) {
        //如果listener为空,说明不需要监听,不为空则在本地监听后,再传出去
        DownloadObserver observer = new DownloadObserver(info, listener == null ? null : new LocalTaskListener());
        synchronized (this) {
            taskMap.put(info, observer);
        }
        OkHttpClient httpClient = HttpUtils.initHttpsClient(true, new OkHttpClient.Builder())
                .addInterceptor(new ProgressInterceptor(observer))
                .build();
        new Retrofit.Builder()
                .client(httpClient)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(info.getBaseUrl())
                .build()
                .create(DownloadService.class)
                .download("bytes=" + info.completionLength + "-", info.url)//断点续传
                .retryWhen(new RetryWhenException())
                .map(responseBodyResponse -> {
                    writeToDisk(responseBodyResponse.body(), info.getTemporaryFile(), info);
                    return responseBodyResponse;
                })
                .compose(SchedulerUtils.applyGeneralObservableSchedulers())
                .subscribe(observer);
    }

    //写入文件在本地
    private void writeToDisk(ResponseBody body, File file, T info) {
        if (body == null) {
            return;
        }
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        InputStream input = body.byteStream();
        long allLen = info.contentLength == 0 ? body.contentLength() : info.contentLength;
        RandomAccessFile accessFile = null;
        FileChannel channel = null;
        try {
            accessFile = new RandomAccessFile(file, "rwd");
            channel = accessFile.getChannel();
            MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, info.completionLength, 
                    allLen - info.completionLength);
            byte[] buffer = new byte[10240];
            int len;
            while ((len = input.read(buffer)) != -1) {
                byteBuffer.put(buffer, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            HttpUtils.closeQuietly(channel, accessFile, input);
        }
    }
        
    private class LocalTaskListener implements DownloadListener {
        @Override
        public void onStateChange(T info, Throwable t) {
            if (listener != null) {
                listener.onStateChange(info, t);
            }
            if (totalTasks > 1) {
                if (info.state == TaskInfo.State.COMPLETED) {
                    taskMap.remove(info);
                    successNum++;                    
                } else if (info.state == TaskInfo.State.CANCEL || info.state == TaskInfo.State.ERROR) {
                    taskMap.remove(info);
                    failureNum++;
                } else if (info.state != TaskInfo.State.START) {
                    return;
                }
                if (listener instanceof MultiDownloadListener) {
                    ((MultiDownloadListener) listener).onTotalProgress(successNum, failureNum, totalTasks);
                }
            }
        }

        @Override
        public void onProgress(T info) {
            if (listener != null) {
                listener.onProgress(info);
            }
        }
    }

    /**
     * 取消所有下载
     */
    @Override
    public void dispose() {
        cancel();
    }

    /**
     * 是否已取消
     */
    @Override
    public boolean isDisposed() {
        return false;
    }

    /**
     * 取消单个下载
     */
    public synchronized void cancel(T info) {
        DownloadObserver observer = taskMap.remove(info);
        if (observer != null) {
            observer.dispose(true);
            if (taskMap.isEmpty()) {
                isCanceled = true;
            }
        }
    }

    /**
     * 取消所有下载
     */
    public synchronized void cancel() {
        if (!taskMap.isEmpty()) {
            for (DownloadObserver observer : taskMap.values()) {
                observer.dispose(true);
            }
            taskMap.clear();
            isCanceled = true;
        }
    }

    /**
     * 是否已取消
     */
    public boolean isCanceled() {
        return isCanceled;
    }

    /**
     * 进行中的下载任务数
     */
    public int remaining() {
        return taskMap.size();
    }

    /**
     * 任务是否正在进行
     */
    public boolean isOngoing() {
        return remaining() > 0;
    }

    /**
     * 恢复单个下载
     */
    public synchronized void resume(T info) {
        if (info.state == TaskInfo.State.PAUSE) {
            execute(info);
        }
    }

    /**
     * 恢复所有下载
     */
    public synchronized void resume() {
        for (T t : taskMap.keySet()) {
            if (t.state == TaskInfo.State.PAUSE) {
                execute(t);
            }
        }
    }

    /**
     * 暂停单个下载
     */
    public synchronized void pause(T info) {
        DownloadObserver observer = taskMap.get(info);
        if (observer != null) {
            observer.dispose(false);
        }
    }

    /**
     * 暂停所有下载
     */
    public synchronized void pause() {
        for (DownloadObserver observer : taskMap.values()) {
            observer.dispose(false);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy