okhttp单线程下载和多线程下载

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_24675479/article/details/79804700

单点下载

  OkHttpManager okHttpManager = new OkHttpManager();
        Call call = okHttpManager.asyncCall("http://acj3.pc6.com/pc6_soure/2018-3/com.ss.android.essay.joke_689.apk");
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // 不断的读写文件,单线程
                InputStream inputStream = response.body().byteStream();

                File file = new File(getCacheDir(),"nhdz.apk");

                OutputStream outputStream = new FileOutputStream(file);

                int len = 0;
                byte[] buffer = new byte[1024*22];

                while ((len = inputStream.read(buffer))!=-1){
                    outputStream.write(buffer,0,len);
                }

                inputStream.close();
                outputStream.close();
               //安装已经下好的apk
                installFile(file);
            }
        });

OkHttpManager

 public Call asyncCall(String url) {

        Request request = new Request.Builder().url(url).build();
        return okHttpClient.newCall(request);
    }

installFile代码

  private void installFile(File file) {
        Intent intent = new Intent("android.intent.action.INSTALL_PACKAGE");
        intent.setData(Uri.parse("file:" + file));
        startActivity(intent);
    }

多线程下载

FileManager文件管理

public class FileManager {
    public static final FileManager manager = new FileManager();
    private File mRootDir;
    private Context mContext;

    private FileManager() {

    }

    public static FileManager getInstance() {
        return manager;
    }

    public void init(Context context) {
        this.mContext = context.getApplicationContext();
    }

    public void rootDir(File file) {
        if (!file.exists()) {
            file.mkdirs();
        }
        if (file.exists() && file.isDirectory()) {
            mRootDir = file;
        }
    }

    /**
     * 根据url生成文件
     */
    public File getFile(String url) {
        String fileName = Utils.md5Url(url)+".apk";
        if (mRootDir == null) {
            mRootDir = mContext.getCacheDir();
        }
        File file = new File(mRootDir, fileName);
        return file;
    }
}

Utils:MD5的加密和关闭流

public class Utils {
    /**
     * md5加密
     */

    public static String md5Url(String url) {
        if (TextUtils.isEmpty(url)) {
            return url;
        }
        StringBuffer sb = new StringBuffer();
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("md5");
            messageDigest.update(url.getBytes());
            byte[] digest = messageDigest.digest();
            for (byte b : digest) {
                // 转成了 16 机制
                String hexStr = Integer.toHexString(b & 0xff);
                //不足补0
                sb.append(hexStr.length() == 0 ? "0" + hexStr : hexStr);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 关闭流
     */
    public static void close(Closeable closeable) {
       if(closeable!=null){
           try {
               closeable.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }

    }
}

DownloadCallback下载接口回调

public interface DownloadCallback {
    public void onFailure(IOException e);

    void onSucceed(File file);
}

DownloadDispatcher开始下载

public class DownloadDispatcher {
    private static final DownloadDispatcher dispatcher=new DownloadDispatcher();
    /**
     * Ready async calls in the order they'll be run.
     */
    private final Deque<DownloadTask> readyTask = new ArrayDeque<>();

    /**
     * Running asynchronous calls. Includes canceled calls that haven't finished yet.
     */
    private final Deque<DownloadTask> runningTask = new ArrayDeque<>();

    /**
     * Running synchronous calls. Includes canceled calls that haven't finished yet.
     */
    private final Deque<DownloadTask> stopTask = new ArrayDeque<>();

    public static DownloadDispatcher getInstance() {
        return dispatcher;
    }

    //1.多线程下载,使用线程池
    public void startDownload(final String url, final DownloadCallback callback) {
        //2.获取文件大小
        Call call = OkHttpManager.getInstance().asyncCall(url);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                callback.onFailure(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //获取文件大小
                long contentLength = response.body().contentLength();
                //没有直接返回
                if (contentLength <= -1) {
                    return;
                }
                //每个线程负责每一块
                DownloadTask downloadTask = new DownloadTask(url, contentLength, callback);
                downloadTask.init();

                runningTask.add(downloadTask);
            }
        });
    }

    public void recyclerTask(DownloadTask downloadTask) {
        runningTask.remove(downloadTask);
        //可以参考okhttp的dispatch的源码,如果还需要下载的开始下一个下载
    }

}

DownloadTask一个apk的下载


public class DownloadTask {
    private String mUrl;
    private long mContentLength;
    private List<DownloadRunnable> mRunnables;//有多个线程下载
    private
    @Nullable
    ExecutorService executorService;
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    //有四个线程下载
    private static final int THREAD_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private DownloadCallback mCallback;
    private volatile int mSucceedNumber = 0;

    public DownloadTask(String url, long contentLength, DownloadCallback callback) {
        this.mContentLength = contentLength;
        this.mUrl = url;
        mRunnables = new ArrayList<>();
        mCallback = callback;
    }

    public synchronized ExecutorService executorService() {
        if (executorService == null) {
            executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(), new ThreadFactory() {
                @Override
                public Thread newThread(@NonNull Runnable runnable) {
                    Thread thread = new Thread(runnable, "okHttp");
                    thread.setDaemon(false);//无守护线程
                    return thread;
                }
            });
        }
        return executorService;
    }

    public void init() {
        for (int i = 0; i < THREAD_SIZE; i++) {
            //每个线程要下载的内容,假设一共4M,每个线程负责1M
            long threadsize = mContentLength / THREAD_SIZE;//每个线程负责下载的大小
            //这里要读取数据库,不能这么写
            long start = i * threadsize;
            long end = (i + threadsize) - 1;
            //最后一个线程可能字节没有threadsize大小
            if (i == THREAD_SIZE - 1) {
                end = mContentLength - 1;
            }
            DownloadRunnable runnable = new DownloadRunnable(mUrl, i, start, end, new DownloadCallback() {
                @Override
                public void onFailure(IOException e) {
                    mCallback.onFailure(e);
                }

                @Override
                public void onSucceed(File file) {
                    //线程同步一下
                   synchronized (DownloadTask.this){
                       mSucceedNumber += 1;
                       if(mSucceedNumber==THREAD_SIZE){
                           mCallback.onSucceed(file);
                           //完成之后回收
                           DownloadDispatcher.getInstance().recyclerTask(DownloadTask.this);
                           //清除这个文件中的数据库
                       }
                   }
                }
            });
            //通过线程池去执行
            executorService().execute(runnable);
        }
    }
    public void stop(String url){
        for (DownloadRunnable runnable : mRunnables) {
            runnable.stop();
        }
    }
}

一个apk多线程下载

ublic class DownloadRunnable implements Runnable {
    private static final int STATUS_DOWNLOAIND = 1;
    private static final int STATUS_STOP = 2;
    private String mUrl;
    private long mStart;
    private long mEnd;
    private int mThreadId;
    private DownloadCallback mCallback;
    private int mStatus = STATUS_DOWNLOAIND;
    private int mProgress = 0;

    public DownloadRunnable(String url, int threadId, long start, long end, DownloadCallback callback) {
        this.mUrl = url;
        this.mStart = start;
        this.mEnd = end;
        this.mThreadId = threadId;
        this.mCallback = callback;
    }

    @Override
    public void run() {
        //只读写我们自己的内容
        RandomAccessFile accessFile = null;
        InputStream inputStream = null;
        try {
            Response response = OkHttpManager.getInstance().syncResponse(mUrl, mStart, mEnd);
            Log.e("TAG", this.toString());

            inputStream = response.body().byteStream();
            //读写数据
            File file = FileManager.manager.getFile(mUrl);
            accessFile = new RandomAccessFile(file, "rwd");

            //从什么位置开始写
            accessFile.seek(mStart);
            int len = 0;
            byte[] buffer = new byte[1024 * 22];

            while ((len = inputStream.read(buffer)) != -1) {
                if (mStatus == STATUS_STOP)
                    break;
                //保存进度,做进度
                mProgress += len;

                accessFile.write(buffer, 0, len);
            }
            mCallback.onSucceed(file);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            Utils.close(inputStream);
            Utils.close(accessFile);
            //存到数据库
        }
    }

    @Override
    public String toString() {
        return "DownloadRunnable{" +
                ", mStart=" + mStart +
                ", mEnd=" + mEnd +
                ", mThreadId=" + mThreadId +
                '}';
    }

    public void stop() {
        mStatus = STATUS_STOP;
    }
}

测试

  FileManager.getInstance().init(this);
        DownloadDispatcher.getInstance().startDownload("http://acj3.pc6.com/pc6_soure/2018-3/com.ss.android.essay.joke_689.apk"
                , new DownloadCallback() {
                    @Override
                    public void onFailure(IOException e) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onSucceed(File file) {

                        installFile(file);
                    }
                });

猜你喜欢

转载自blog.csdn.net/qq_24675479/article/details/79804700
今日推荐