閱讀467 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Android 經典筆記之五:DownloadManager下載管理器介紹

DownloadManager下載管理器介紹
目錄介紹:

  • 0.簡單介紹
  • 1.所需權限
  • 2.獲取對象,開始下載
  • 3.取消下載
  • 4.Request類的介紹
    • 4.5.指定下載的類型
    • 4.6.定製Notification樣式
    • 4.7.設置下載文件類型
    • 4.8.添加請求下載的網絡鏈接的http頭,比如User-Agent,gzip壓縮等
  • 5.Query 類
  • 6.不足之處
  • 7.代碼案例【簡易】

0.簡單介紹

  • 關於DownloadManager簡單介紹 DownloadManager是android2.3以後,係統下載的方法,是處理長期運行的HTTP下載的係統服務。客戶端可以請求的URI被下載到一個特定的目標文件。客戶端將會在後台與http交互進行下載,或者在下載失敗,或者連接改變,重新啟動係統後重新下載。還可以進入係統的下載管理界麵查看進度。DownloadManger有兩個內部類,Request 和Query。Request類可設置下載的一些屬性。Query類可查詢當前下載的進度,下載地址,文件存放目錄等數據。

1.所需權限

<uses-permission android:name="android.permission.INTERNET" />;
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>;

注意,訪問本地控件【sd卡,手機內存卡】需要檢測是否添加權限

/**檢測存儲權限*/
private final int REQUEST_EXTERNAL_STORAGE = 1;
private String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

public void verifyStoragePermissions(Activity activity) {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
    }
}

2.獲取對象,開始下載

  • 獲取對象,開始下載 DownloadManager downloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl)); long id = downloadManager.enqueue(request); //每下載的一個文件對應一個id,通過此id可以查詢數據。

3.取消下載

downloadManager.remove(REFERENCE_1, REFERENCE_2, REFERENCE_3);
該方法返回成功取消的下載的個數,如果一個下載被取消了,所有相關聯的文件,部分下載的文件和完全下載的文件都會被刪除.

4.Request類的介紹

/**
* 方法1:
* 目錄: Android -> data -> com.app -> files -> Download -> dxtj.apk
* 這個文件是你的應用所專用的,軟件卸載後,下載的文件將隨著卸載全部被刪除
*/
request.setDestinationInExternalFilesDir( this , Environment.DIRECTORY_DOWNLOADS ,  "dxtj.apk" );
/**
* 方法2:
* 下載的文件存放地址  SD卡 download文件夾,dxtj.apk
* 軟件卸載後,下載的文件會保留
*/
//在SD卡上創建一個文件夾
request.setDestinationInExternalPublicDir(  "/epmyg/"  , "dxtj.apk" ) ;
/**
* 方法3:
* 如果下載的文件希望被其他的應用共享
* 特別是那些你下載下來希望被Media Scanner掃描到的文件(比如音樂文件)
*/
request.setDestinationInExternalPublicDir( Environment.DIRECTORY_MUSIC,  "告白氣球.mp3" );
/**
* 方法4【投資界和新芽目前用這個】
* 文件將存放在外部存儲的確實download文件內,如果無此文件夾,創建之,如果有,下麵將返回false。
* 係統有個下載文件夾,比如小米手機係統下載文件夾  SD卡--> Download文件夾
*/
//創建目錄
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).mkdir() ;
//設置文件存放路徑
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS  , "dxtj.apk" ) ;
  • 4.1 指定下載的類型

    //指定在WIFI狀態下,執行下載操作。
    request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
    //指定在MOBILE狀態下,執行下載操作
    request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE);
    //是否允許漫遊狀態下,執行下載操作
    request.setAllowedOverRoaming(boolean);
    //是否允許“計量式的網絡連接”執行下載操作
    request.setAllowedOverMetered(boolean); //默認是允許的。
    
  • 4.2 定製Notification樣式

    //設置Notification的標題和描述
    request.setTitle("標題"); 
    request.setDescription("描述");
    //設置Notification的顯示,和隱藏。
    request.setNotificationVisibility(visibility);
    VISIBILTY_HIDDEN: Notification:將不會顯示,如果設置該屬性的話,必須要添加權限
    android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
    VISIBILITY_VISIBLE: Notification顯示,但是隻是在下載任務執行的過程中顯示,下載完成自動消失。(默認值)
    VISIBILITY_VISIBLE_NOTIFY_COMPLETED : Notification顯示,下載進行時,和完成之後都會顯示。
    VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION :隻有當任務完成時,Notification才會顯示。
    對Notification的設定方法相對較少。
    
  • 4.3 設置下載文件類型

    request.setMimeType("application/vnd.android.package-archive");
    這是安卓.apk文件的類型。有些機型必須設置此方法,才能在下載完成後,點擊通知欄的Notification時,才能正確的打開安裝界麵。不然會彈出一個Toast(can not open file).其他文件類型的MimeType
    
  • 4.4 添加請求下載的網絡鏈接的http頭,比如User-Agent,gzip壓縮等

    request.addRequestHeader(String header, String value);
    

5.Query 類

  • 我們的需求,可能不隻是在Notification 中顯示進度就好了,也許,在app中也需要獲取實時下載進度。所以Query類就是提供查詢的一些方法。
  • 但API中就隻有兩個方法,原來,他把數據保存在數據庫中去了。我們需要獲得一個Cursor 結果集,通過結果集獲得我們想要的數據。 DownloadManager.Query query = new DownloadManager.Query(); Cursor cursor = downloadManager.query(query.setFilterById(id)); if (cursor != null && cursor.moveToFirst()) { //下載的文件到本地的目錄 String address = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); //已經下載的字節數 int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); //總需下載的字節數 int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); //Notification 標題 String title =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE)); //描述 String description =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION)); //下載對應id long id =cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID)); //下載文件名稱 String filename =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME)); //下載文件的URL鏈接 String url =cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI)); }

6.不足之處

  • 1、我發現,在下載的時候,發送Notification時 是沒有聲音的。也沒有設置聲音的方法。不過這影響不大。主要的功能實現就好。
  • 2、因為這是係統的類,每個係統的Notification界麵是不一樣的。這就是每個rom廠家的自定義了。小米和魅族的就大不一樣。魅族Notification上有一個下載暫停的按鈕,而小米沒有。所以導致Notification是不能統一的。其實,暫停的話用戶可以點擊notification,進入到下載管理界麵,就有暫停按鈕了。

7.代碼案例【簡易】

/**
* 開始下載
* @param context
*/
private static void startDownload(Context context) {
    int status = getDownloadStatus(context);
    if (status != DOWNLOAD_STATUS_NEED_LOAD) {
        // 不用下載則無需下列操作
        return;
    }

    DialogUtils.showToast(context, "開始下載安裝包...");
    // parse url
    Uri mUri = Uri.parse(path);
    // create request
    DownloadManager.Request r = new DownloadManager.Request(mUri);
    // set request property
    String apkName = getDownloadApkName(context);
    // set 下載路徑
    r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);
    // set Notification
    r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    // create manager
    DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    // key code, set mine type
    r.setMimeType("application/vnd.android.package-archive");
    // add to queue
    dm.enqueue(r);
}

/**獲得Apk的名稱*/
@NonNull
private static String getDownloadApkName(Context context) {
    return context.getString(R.string.app_name) + "_" + version + ".apk";
}

/**
* 判斷當前版本文件下載狀態
* @param context
* @return
*/
private static int getDownloadStatus(Context context) {
    DownloadManager.Query query = new DownloadManager.Query();
    DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);
    Cursor c = dm.query(query);

    if (!c.moveToFirst()) {
        // 無下載內容
        return DOWNLOAD_STATUS_NEED_LOAD;
    }

    do {
        int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
        String title = c.getString(c.getColumnIndex(DownloadManager.COLUMN_TITLE));
        String apkName = getDownloadApkName(context);
        if (title.equals(apkName)) {
            // 如果下載列表中文件是當前版本應用,則繼續判斷下載狀態
            if (status == DownloadManager.STATUS_SUCCESSFUL) {
                // 如果已經下載,返回狀態,同時直接提示安裝
                String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                promptInstall(context, Uri.parse(uri));
                return DOWNLOAD_STATUS_LOADED;
            } else if (status == DownloadManager.STATUS_RUNNING
                    || status == DownloadManager.STATUS_PAUSED
                    || status == DownloadManager.STATUS_PENDING) {
                return DOWNLOAD_STATUS_RUNNING;
            } else {
                // 失敗也視為可以再次下載
                return DOWNLOAD_STATUS_NEED_LOAD;
            }
        }
    } while (c.moveToNext());
    return DOWNLOAD_STATUS_NEED_LOAD;
}

/**
* 根據下載隊列id獲取下載Uri
* @param enqueueId
* @return null-獲取不到
*/
public static Uri getDownloadUriById(Context context, long enqueueId) {
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(enqueueId);
    DownloadManager dm = (DownloadManager) context.getSystemService(Activity.DOWNLOAD_SERVICE);
    Cursor c = dm.query(query);
    if (c.moveToFirst()) {
        int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
        if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
            String uri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
            return Uri.parse(uri);
        }
    }
    return null;
}

/**
* 安裝文件
* @param context      上下文
* @param data          uri地址
*/
public static void promptInstall(Context context, Uri data) {
    Intent promptInstall = new Intent(Intent.ACTION_VIEW).setDataAndType(data, "application/vnd.android.package-archive");
    // FLAG_ACTIVITY_NEW_TASK 可以保證安裝成功時可以正常打開 app
    promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(promptInstall);
}

其他

最後更新:2017-09-20 10:02:55

  上一篇:go  使用hexo在GitHub上搭建個人博客網站
  下一篇:go  Android 經典筆記六:Annotation注釋使用介紹