Androidのマルチスレッドダウンロードダウンロードは原則横暴を解析したファイルは、(3)-----文書をご紹介します

1.まず、ここからダウンロードを作成 - URLに基​​づいてファイルを作成します。

  /**
 * <p>Title: FlieStorageManager</p >
 * <p>Description: TODO</p >
 * <p>Company: ihaveu</p >
 *
 * @author MaWei
 * @date 2018/2/5
 */
public class FlieStorageManager {

    public static FlieStorageManager sManager = new FlieStorageManager();

    private Context mContext;

    public static FlieStorageManager getInstance(){
        return sManager;
    }

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

    public FlieStorageManager() {
    }

    /**
     * 根据url 设置文件名返回文件
     * @param url
     * @return
     */
    public File getFileByName(String url){
        File parent;
        // 判断手机有没有挂载SD卡
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            // 通过Context.getExternalCacheDir()方法可以获取到 SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
            parent = mContext.getExternalCacheDir();
        }else {
            // 没有SD卡保存在系统目录的cache下
            parent = mContext.getCacheDir();
        }

        String fileName = Md5Uills.generateCode(url);
        // 路径、 文件名
        File file = new File(parent, fileName);
        if(!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return file;
    }

}

私たちのパスの下にCACHディレクトリに明確です。

その後、我々はいくつかの簡単なパッケージ要求フレームokhttpネットワークを見てください。
そして、一見シンプルに皆のためのシングルスレッドのダウンロードを達成する方法であります

/**
 * <p>Title: HttpManager</p >
 * <p>Description: 联网请求工具类</p >
 * <p>Company: ihaveu</p >
 *
 * @author MaWei
 * @date 2018/2/5
 */
public class HttpManager {

    public static HttpManager mManager = new HttpManager();
    /** 请求失败*/
    public static final int NETWORK_ERROR_CODE = 1;
    /** 获取不到文件的总长度*/
    public static final int CONTENT_LENGTH_ERROR_CODE = 2;
    /** 队列中存在下载的任务*/
    public static final int TASK_RUNNING_ERROR_CODE = 3;
    /** okhttp请求类*/
    private OkHttpClient mClient;
    private Context mContext;

    private void init(Context mContext){
        this.mContext = mContext;
    }

    public HttpManager() {
        this.mClient = new OkHttpClient();
    }

    public static HttpManager getInstance(){
        return mManager;
    }

    /**
     * 同步请求
     *
     * @param url
     * @return
     */
    public Response syncRequest(String url) {
        Request request = new Request.Builder().url(url).build();
        try {
            return mClient.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 同步请求(根据指定位置下载)
     * 根据请求头 Range字段 指定下载的位置
     */
    public Response syncRequestByRange(String url, long start, long end) {
        Request request = new Request.Builder().url(url)
                .addHeader("Range", "bytes=" + start + "-" + end)
                .build();
        try {
            return mClient.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 异步调用
     * @param url
     * @param callback
     */
    public void asyncRequest(final String url, Callback callback) {
        Request request = new Request.Builder().url(url).build();
        mClient.newCall(request).enqueue(callback);
    }


    /**
     * 异步请求(单线程下载)
     */
    public void asyncSingleThreadRequest(final String url, final DownLoadCallBack callback) {
        Request request = new Request.Builder().url(url).build();
        // okhttp的异步请求
        mClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                if (!response.isSuccessful() && callback != null) {
                    callback.fail(NETWORK_ERROR_CODE, "请求失败");
                }

                // 根据url创建一个文件
                File file = FlieStorageManager.getInstance().getFileByName(url);

                // 创建字节数组,以这个字节数组 读写
                byte[] buffer = new byte[1024 * 500];
                int len;
                FileOutputStream fileOut = new FileOutputStream(file);
                // 返回的response转成数据流
                InputStream inStream = response.body().byteStream();
                // 读取返回数据流 写到创建的文件中
                while ((len = inStream.read(buffer, 0, buffer.length)) != -1) {
                    fileOut.write(buffer, 0, len);
                    fileOut.flush();
                }
                // 写入完成
                callback.success(file);

            }
        });
    }
}

そして、私たちのコールバックインタフェースを見てみましょう。

/**
 * <p>Title: DownLoadCallBack</p >
 * <p>Description: TODO</p >
 * <p>Company: ihaveu</p >
 *
 * @author MaWei
 * @date 2018/2/5
 */
public interface DownLoadCallBack {

    void success(File file);

    void fail(int errorCode, String errorMessage);

    void progress(int progress);
}

私はokhttpシンプルなツールを封印HttpManagerを見ることができます。同期のためのツールは、コールバック、非同期コールバックを要求します。

私はまた、あなたのシングルスレッドのダウンロードの簡単な例を感謝します。それは、我々は直接このメソッドは、シングルスレッドの方法である)(asyncSingleThreadRequestを呼び出すです。私が書いたコメントや内部では、私はそれを理解するための非常にシンプルな外観を信じています。

シングルスレッドのダウンロードビジネスプロセス:URLによると、ファイルを作成し、その後、** response.body(非同期コールバック要求に応答することによって)byteSream()、応答データ・ストリーム変換した後、我々は、ストリームの形式で書きますファイル。

OK、我々は、以下の操作を続行します。

私たちは、その後、マルチスレッドのダウンロード管理クラスを作成します。

/**
 * <p>Title: DownloadManager</p >
 * <p>Description: 下载、线程管理类</p >
 * <p>Company: ihaveu</p >
 *
 * @author MaWei
 * @date 2018/2/6
 */
public class DownloadManager {

    private static DownloadManager mManager = new DownloadManager();
    /** 核心和最大线程数量*/
    private final static int MAX_THREAD = 2;

    /**
     * 创建线程池
     * 参数1:核心线程数量
     * 参数2:线程池最大数量
     * 参数3:线程存活时间
     * 参数4:设置时间等级
     * 参数5:先不管
     * 原理:线程池首先会创建核心线程, 如果在执行时,超过最大数量会抛出异常
     */
    private static final ThreadPoolExecutor sThreadPool = new ThreadPoolExecutor(MAX_THREAD, MAX_THREAD, 60,
            TimeUnit.MICROSECONDS, new LinkedBlockingDeque<Runnable>(), new ThreadFactory() {

        private AtomicInteger mInteger = new AtomicInteger(1);
        @Override
        public Thread newThread(Runnable runnable) {
            // 指定Runnable  和线程名称
            Thread mThread = new Thread(runnable, "download thread #" + mInteger.getAndIncrement());
            return mThread;
        }
    });

    public static DownloadManager getInstance(){
        return mManager;
    }

    public DownloadManager() {
    }

    /**
     * 判断每个线程下载多长的数据,并多线程下载
     */
    public void downLoad(final String url, final DownLoadCallBack callBack){
        HttpManager.getInstance().asyncRequest(url, new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response == null && callBack != null) {
                    callBack.fail(HttpManager.NETWORK_ERROR_CODE, "网络出问题了");
                    return;
                }

                long length = response.body().contentLength();
                if(length == -1) {
                    // 获取不到文件的总长度
                    callBack.fail(HttpManager.CONTENT_LENGTH_ERROR_CODE, "contenLength -1");
                    return;
                }

                processDownload(url, length, callBack);
            }
        });
    }

    /**
     * 下载
     * @param length     下载文件的长度
     */
    private void processDownload(String url, long length, DownLoadCallBack callBack) {
        // 计算每一个线程下载的大小
        long threadDownloadSize = length / MAX_THREAD;
        // 分配每一个线程下载
        for(int i = 0; i < MAX_THREAD; i++) {
            // 计算每一个线程从多少下载 比如长度100  2个线程  0-49  50-99, 下面是计算的算法
            long startSize = i * threadDownloadSize;
            long endSize = (i + 1) * threadDownloadSize - 1;

            // 执行下载
            sThreadPool.execute(new DownloadRunnable(startSize, endSize, url, callBack));
        }
    }
}

要約:最初にスレッド2を管理するスレッドプールに、スレッドの最大数をコアスレッドのスレッドを作成します。
その後、我々は、ダウンロードするファイルにアクセスするファイルの合計の長さを取り戻す、その後、スレッドの数に応じて、ダウンロードする各スレッドの長さを分割して、スレッドプールでファイルをダウンロードするための非同期要求を開始します。

OK、スレッドクラスのコアで見てみましょうを実行する方法です。

/**
 * <p>Title: DownloadRunnable</p >
 * <p>Description: 下载执行的线程</p >
 * <p>Company: ihaveu</p >
 *
 * @author MaWei
 * @date 2018/2/6
 */
public class DownloadRunnable  implements Runnable{

    /** 指定下载开始位置*/
    private long mStart;
    /** 指定下载结束位置*/
    private long mEnd;
    /** 请求url*/
    private String mUrl;
    /** 结果回调*/
    private DownLoadCallBack mCallBack;

    public DownloadRunnable(long mStart, long mEnd, String mUrl, DownLoadCallBack mCallBack) {
        this.mStart = mStart;
        this.mEnd = mEnd;
        this.mUrl = mUrl;
        this.mCallBack = mCallBack;
    }

    @Override
    public void run() {
        // 下载完成后返回的结果 response
        Response response = HttpManager.getInstance().syncRequestByRange(mUrl, mStart, mEnd);

        if(response == null && mCallBack != null) {
            mCallBack.fail(HttpManager.NETWORK_ERROR_CODE, "网络出问题了");
            return;
        }

        // 获取本地下载储存的文件
        File file = FlieStorageManager.getInstance().getFileByName(mUrl);

        // 多个线程对文件指定的位置写入数据(因为是多线程下载,多个线程肯定会对一个文件可读 可写 可修改)
        try {
            // 参数1:指定操作的文件  参数2:可读 可写 可修改
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rwd");
            // 指定一个偏移,下载的起始位置
            randomAccessFile.seek(mStart);
            byte[] buffer = new byte[1024];
            int len = 0;
            InputStream inputStream = response.body().byteStream();
            // 读取返回来的数据, 写入本地文件中
            while((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
                randomAccessFile.write(buffer, 0, len);
            }

            // 下载成功
            mCallBack.success(file);

        } catch (FileNotFoundException e) {

            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

それはマルチスレッドであるため、これは、スレッドプールによってRunnable実行され、スレッドのrunメソッドを参照して、URLがファイルを使用して作成し、このファイルを介してのRandomAccessFileファイルを変換され、目的は、指定された場所に書き込みデータファイルを」より多くのスレッド(ありますダウンロード複数のスレッドは確か)読み書き可能なファイルを変更することができること「との任意の場所からダウンロードしたファイルの開始を指定することによってファイルを図ってまいります。だから、別のスレッドがOK上の別の場所をダウンロードする必要があります。しかし、必要がマルチスレッドのダウンロードは同期動作であるが、ことを思い出すことにします。

OKのでマルチスレッドダウンロードのみ直接呼び出しに必要な、我々はあなたが必要とするマルチスレッドダウンロードを達成することができ、完了です。
(マルチスレッドダウンロード、ダウンロードが完了したImageViewの上に表示されている)の例:

   private void multipleDownFileImage() {
        DownloadManager.getInstance().downLoad("http://szimg.mukewang.com/5763765d0001352105400300-360-202.jpg", new DownLoadCallBack() {
            @Override
            public void success(final File file) {
                Log.e("file", "file success: " + file.getAbsolutePath());
                Log.e("file", "file : " + file.length());

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
                        image.setImageBitmap(bitmap);
                    }
                });
            }

            @Override
            public void fail(int errorCode, String errorMessage) {

            }

            @Override
            public void progress(int progress) {

            }
        });
    }

その後、私は、データベースのストレージとデータがダウンロードされ、あなたにいくつかの局所的な最適化を与え、その後、ダウンロードしていきます、ダイレクトコピーコードの必要性を使用することができますがあります。滞在が調整されました!

公開された51元の記事 ウォン称賛78 ビュー30000 +

おすすめ

転載: blog.csdn.net/weixin_39079048/article/details/79320371