下載工具類 - 基于 HttpURLConnection

使用方法和源代碼看注釋

package com.geaosu.alearn;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/*

=========================== 該工具類的用法 ===========================
=========================== 該工具類的用法 ===========================
=========================== 該工具類的用法 ===========================

    // 錘子便簽
    String url = "https://01911f43fa7455a7a99a61cc172fc905.dd.cdntips.com/imtt.dd.qq.com/16891/apk/15A873B930E4EDF0A772A67566516D38.apk?mkey=5f4778860e864886&f=0f1d&fsname=com.smartisan.notes_3.7.2_47.apk&csr=1bbd&cip=14.134.110.115&proto=https";

    // 調(diào)用方法一
    DownloadUtils.getInstance()
            .setUrl(url)
            .setDirPath("/sdcard/Download/")
            .setFileName("錘子便簽")
            .setOnDownloadListener(new DownloadUtils.OnDownloadListener() {
                @Override
                public void onStart() {

                }

                @Override
                public void onProgress(int fileTotalSize, int progress) {

                }

                @Override
                public void onFinish(File file) {

                }

                @Override
                public void onError(String errMsg) {

                }
            });


    // 調(diào)用方法二
    DownloadUtils instance = DownloadUtils.getInstance();
    instance.downLoadFile(url, "/sdcard/Download/", "錘子便簽", new DownloadUtils.OnDownloadListener() {
        @Override
        public void onStart() {

        }

        @Override
        public void onProgress(int fileTotalSize, int progress) {

        }

        @Override
        public void onFinish(File file) {

        }

        @Override
        public void onError(String errMsg) {

        }
    });


=========================== 該工具類的用法 ===========================
=========================== 該工具類的用法 ===========================
=========================== 該工具類的用法 ===========================

*/

/**
 * 下載工具
 */
public class DownloadUtils {
    private static final String TAG = "DownloadUtils";
    private static Context mContext;
    private static DownloadUtils mDownloadUtils;
    private static ThreadUtils mThreadUtils;


    private String mDownloadUrl;
    private String mDriPath;
    private String mFileName;


    private DownloadUtils() {

    }


    // 獲取對象
    public static DownloadUtils getInstance() {
        if (mThreadUtils == null) {
            mThreadUtils = new ThreadUtils();
        }
        if (mDownloadUtils == null) {
            mDownloadUtils = new DownloadUtils();
        }
        return mDownloadUtils;
    }


    // 設(shè)置下載地址
    public DownloadUtils setUrl(String downloadUrl) {
        if (downloadUrl == null) {
            throw new NullPointerException("url is a null");
        }
        this.mDownloadUrl = downloadUrl;
        return mDownloadUtils;
    }


    // 設(shè)置下載文件夾
    public DownloadUtils setDirPath(String dirPath) {
        if (dirPath == null) {
            throw new NullPointerException("dirPath is a null");
        }
        this.mDriPath = dirPath;
        return mDownloadUtils;
    }


    // 設(shè)置下載文件名稱
    public DownloadUtils setFileName(String fileName) {
        if (fileName == null) {
            throw new NullPointerException("fileName is a null");
        }
        this.mFileName = fileName;
        return mDownloadUtils;
    }


    // 設(shè)置下載進度回調(diào)監(jiān)聽
    public void setOnDownloadListener(OnDownloadListener listener) {
        if (listener == null) {
            throw new NullPointerException("OnDownloadListener is a null");
        }
        downLoadFile(mDownloadUrl, mDriPath, mFileName, listener);
    }


    /**
     * 下載文件
     *
     * @param downloadUrl
     * @param driPath
     * @param fileName
     * @param listener
     * @return file對象
     */
    public void downLoadFile(String downloadUrl, String driPath, String fileName, OnDownloadListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 先判空, 保證參數(shù)無誤
                if (TextUtils.isEmpty(downloadUrl) || TextUtils.isEmpty(driPath) || TextUtils.isEmpty(fileName)) {
                    throw new NullPointerException("downloadUrl is a null");
                }
                if (TextUtils.isEmpty(driPath) || TextUtils.isEmpty(fileName)) {
                    throw new NullPointerException("driPath is a null");
                }
                if (TextUtils.isEmpty(fileName)) {
                    throw new NullPointerException("fileName is a null");
                }
                if (listener == null) {
                    throw new NullPointerException("OnDownloadListener is a null object");
                }


                // 輸出一下下載信息
                Log.d("gLog", TAG + " - 文件下載 ------>> 文件下載地址: " + downloadUrl);
                Log.d("gLog", TAG + " - 文件下載 ------>> 文件保存路徑: " + driPath);
                Log.d("gLog", TAG + " - 文件下載 ------>> 文件保存名稱: " + fileName);


                mThreadUtils.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        listener.onStart();
                    }
                });


                // 下載準備
                int downloadedSize = 0;        // 已經(jīng)下載的文件大小
                int fileTotalSize = 0;         // 文件總大小


                // 文件夾準備
                File file = new File(driPath);
                if (!file.exists()) {           // 判斷文件夾是否存在
                    if (!file.mkdirs()) {       // 文件夾不存在, 創(chuàng)建
                        mThreadUtils.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                listener.onError("無法創(chuàng)建文件夾");
                            }
                        });
                        return;
                    }
                }


                // 文件全路徑 = 文件夾+文件名+后綴
                file = new File(driPath + File.separator + fileName);
                if (file == null) {
                    mThreadUtils.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            listener.onError("無法創(chuàng)建文件");
                        }
                    });
                }


                // 流和鏈接
                InputStream inputStream = null;
                FileOutputStream outputStream = null;
                HttpURLConnection connection = null;


                // 開始鏈接
                try {
                    URL url = new URL(downloadUrl);
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setConnectTimeout(10 * 1000);
                    connection.setReadTimeout(10 * 1000);
                    connection.connect();


                    // 獲取要下載的文件信息
                    fileTotalSize = connection.getContentLength();          // 文件總大小


                    inputStream = connection.getInputStream();
                    outputStream = new FileOutputStream(file);


                    byte[] buffer = new byte[1024 * 4];
                    int len;
                    while ((len = inputStream.read(buffer)) > 0) {
                        outputStream.write(buffer, 0, len);
                        downloadedSize += len;


                        // 計算文件下載進度
                        final int progress = (int) (downloadedSize * 1.0f / fileTotalSize * 100);


                        int finalFileTotalSize = fileTotalSize;
                        mThreadUtils.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                listener.onProgress(finalFileTotalSize, progress);
                            }
                        });
                    }


                    // 下載成功

                    File finalFile = file;
                    mThreadUtils.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            listener.onFinish(finalFile);
                        }
                    });
                } catch (Exception e) {
                    if (file.exists()) {
                        if (file.delete()) {
                            mThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    listener.onError("下載失敗, 失敗信息: " + e.getMessage());
                                }
                            });
                        } else {
                            mThreadUtils.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    listener.onError("下載失敗, 失敗信息: " + e.getMessage());
                                }
                            });
                        }
                    } else {
                        mThreadUtils.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                listener.onError("下載失敗, 失敗信息: " + e.getMessage());
                            }
                        });
                    }
                } finally {
                    try {
                        if (inputStream != null)
                            inputStream.close();
                        if (outputStream != null)
                            outputStream.close();
                        if (connection != null)
                            connection.disconnect();
                    } catch (Exception e) {
                        mThreadUtils.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                listener.onError("IO流關(guān)閉失敗, 失敗信息: " + e.getMessage());
                            }
                        });
                    }
                }
            }
        }).start();
    }


    /**
     * 回調(diào)監(jiān)聽器
     * <p>
     * 所有回調(diào)函數(shù)都運行在主線程
     */
    public interface OnDownloadListener {
        // 開始下載
        void onStart();

        // 正在下載
        void onProgress(int fileTotalSize, int progress);

        // 下載完成
        void onFinish(File file);

        // 下載失敗
        void onError(String errMsg);
    }

    /**
     * 線程切換工具
     */
    private static class ThreadUtils {

        private Handler mHandler = new Handler(Looper.getMainLooper());

        // 在主線程中運行
        public void runOnUiThread(Runnable r) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                //主線程
                r.run();
            } else {
                //子線程
                mHandler.post(r);
            }
        }

        // 在子線程中運行
        public void runOnSubThread(Runnable r) {
            new Thread(r).start();
        }

        // 是否是主線程
        public boolean isMainThread() {
            return Looper.getMainLooper() == Looper.myLooper();
        }
    }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末世蔗,一起剝皮案震驚了整個濱河市重罪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌留晚,老刑警劉巖拙已,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壤躲,死亡現(xiàn)場離奇詭異绪商,居然都是意外死亡坛掠,警方通過查閱死者的電腦和手機咪奖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門盗忱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人羊赵,你說我怎么就攤上這事趟佃∩纫ィ” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵闲昭,是天一觀的道長罐寨。 經(jīng)常有香客問我,道長序矩,這世上最難降的妖魔是什么鸯绿? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮簸淀,結(jié)果婚禮上瓶蝴,老公的妹妹穿的比我還像新娘。我一直安慰自己租幕,他們只是感情好舷手,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著劲绪,像睡著了一般男窟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贾富,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天歉眷,我揣著相機與錄音,去河邊找鬼祷安。 笑死姥芥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汇鞭。 我是一名探鬼主播凉唐,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼霍骄!你這毒婦竟也來了台囱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤读整,失蹤者是張志新(化名)和其女友劉穎簿训,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體米间,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡强品,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了屈糊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片的榛。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逻锐,靈堂內(nèi)的尸體忽然破棺而出雕薪,到底是詐尸還是另有隱情所袁,我是刑警寧澤凶掰,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站局劲,受9級特大地震影響鱼填,放射性物質(zhì)發(fā)生泄漏毅戈。R本人自食惡果不足惜苇经,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一商模、第九天 我趴在偏房一處隱蔽的房頂上張望施流。 院中可真熱鬧瞪醋,春花似錦银受、人聲如沸宾巍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鲜侥。三九已至描函,卻和暖如春舀寓,著一層夾襖步出監(jiān)牢的瞬間互墓,已是汗流浹背篡撵。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留膛檀,地道東北人咖刃。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像磕潮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子膏潮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354