首页 > 代码库 > Android 演示 DownloadManager 下载

Android 演示 DownloadManager 下载

本文内容

  • 环境
  • 项目结构
  • 演示下载
  • 参考资料

本文是 github 上 Trinea-common 和 Trinea-Demo 项目的一部分。(不知道此人攒了多久~ 技术分享

假设,现在有个下载 apk 包的需求,你大概能想到什么?

  • 下载本身;
  • 下载进度;
  • 期间还能取消;
  • 由于网络不好或中断,下载失败,还要能重试;
  • 因为下载的是 apk,下载完还要能提示安装更好,而且,很多手机管理 app,还能静默安装;
  • 还能在手机通知栏看到下载提示;
  • 这些就涉及到 android.app.DownloadManagerandroid.content.BroadcastReceiverandroid.os.Handler

自己下载 Demo 调试一下~

下载 Demo(国外网站,网络不好的多刷新或者设置dl)

更多 Demo

环境


  • Windows 2008 R2 64 位
  • Eclipse ADT V22.6.2,Android 4.4.2(API 19)
  • SAMSUNG GT-8618,Android OS 4.1.2

项目结构


技术分享

图 1 项目结构

技术分享

图 2 主程序

图 2 主程序

技术分享

图 3 下载

(注意:顶部通知栏,是有下载图标的~)

package com.example.download.ui;
 
import java.io.File;
import java.text.DecimalFormat;
import com.example.download.R;
import com.example.download.utils.DownloadManagerPro;
import com.example.download.utils.PreferencesUtils;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
 
/**
 * DownloadManagerDemo
 * 
 * @author LN 
 * @since 2014-1-8
 * @version 1.0
 */
public class DownloadManagerDemo extends Activity {
 
    public static final String DOWNLOAD_FOLDER_NAME = "Trinea";
    public static final String DOWNLOAD_FILE_NAME = "MeiLiShuo.apk";
 
    public static final String APK_URL = "http://img.meilishuo.net/css/images/AndroidShare/Meilishuo_3.6.1_10006.apk";
    public static final String KEY_NAME_DOWNLOAD_ID = "downloadId";
 
    private Button downloadButton;
    private ProgressBar downloadProgress;
    private TextView downloadTip;
    private TextView downloadSize;
    private TextView downloadPrecent;
    private Button downloadCancel;
 
    private DownloadManager downloadManager;
    private DownloadManagerPro downloadManagerPro;
    private long downloadId = 0;
 
    private MyHandler handler;
 
    private DownloadChangeObserver downloadObserver;
    private CompleteReceiver completeReceiver;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.download_manager_demo);
        
        handler = new MyHandler();
        downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        downloadManagerPro = new DownloadManagerPro(downloadManager);
 
        // see android mainfest.xml, 
        // accept minetype of cn.trinea.download.file
        Intent intent = getIntent();
        if (intent != null) {
            /**
             * below android 4.2, intent.getDataString() is
             * file:///storage/sdcard1/Trinea/MeLiShuo.apk<br/>
             * equal or above 4.2 intent.getDataString() is
             * content://media/external/file/29669
             */
            Uri data = http://www.mamicode.com/intent.getData();>

以及自定义的 DownloadManagerPro 和 PreferencesUtils 类,代码如下所示:、

package com.example.download.utils;
 
import java.lang.reflect.Method;
 
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
 
/**
 * DownloadManagerPro
 */
public class DownloadManagerPro {
 
    public static final Uri CONTENT_URI = Uri
            .parse("content://downloads/my_downloads");
    /** represents downloaded file above api 11 **/
    public static final String COLUMN_LOCAL_FILENAME = "local_filename";
    /** represents downloaded file below api 11 **/
    public static final String COLUMN_LOCAL_URI = "local_uri";
 
    public static final String METHOD_NAME_PAUSE_DOWNLOAD = "pauseDownload";
    public static final String METHOD_NAME_RESUME_DOWNLOAD = "resumeDownload";
 
    private static boolean isInitPauseDownload = false;
    private static boolean isInitResumeDownload = false;
 
    private static Method pauseDownload = null;
    private static Method resumeDownload = null;
 
    private DownloadManager downloadManager;
 
    public DownloadManagerPro(DownloadManager downloadManager) {
        this.downloadManager = downloadManager;
    }
 
    /**
     * get download status
     * 
     * @param downloadId
     * @return
     */
    public int getStatusById(long downloadId) {
        return getInt(downloadId, DownloadManager.COLUMN_STATUS);
    }
 
    /**
     * get downloaded byte, total byte
     * 
     * @param downloadId
     * @return a int array with two elements
     *         <ul>
     *         <li>result[0] represents downloaded bytes, This will initially be
     *         -1.</li>
     *         <li>result[1] represents total bytes, This will initially be -1.</li>
     *         </ul>
     */
    public int[] getDownloadBytes(long downloadId) {
        int[] bytesAndStatus = getBytesAndStatus(downloadId);
        return new int[] { bytesAndStatus[0], bytesAndStatus[1] };
    }
 
    /**
     * get downloaded byte, total byte and download status
     * 
     * @param downloadId
     * @return a int array with three elements
     *         <ul>
     *         <li>result[0] represents downloaded bytes, This will initially be
     *         -1.</li>
     *         <li>result[1] represents total bytes, This will initially be -1.</li>
     *         <li>result[2] represents download status, This will initially be
     *         0.</li>
     *         </ul>
     */
    public int[] getBytesAndStatus(long downloadId) {
        int[] bytesAndStatus = new int[] { -1, -1, 0 };
        DownloadManager.Query query = new DownloadManager.Query()
                .setFilterById(downloadId);
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {
                bytesAndStatus[0] = c
                        .getInt(c
                                .getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                bytesAndStatus[1] = c
                        .getInt(c
                                .getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                bytesAndStatus[2] = c.getInt(c
                        .getColumnIndex(DownloadManager.COLUMN_STATUS));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return bytesAndStatus;
    }
 
    /**
     * pause download
     * 
     * @param ids
     *            the IDs of the downloads to be paused
     * @return the number of downloads actually paused, -1 if exception or
     *         method not exist
     */
    public int pauseDownload(long... ids) {
        initPauseMethod();
        if (pauseDownload == null) {
            return -1;
        }
 
        try {
            return ((Integer) pauseDownload.invoke(downloadManager, ids))
                    .intValue();
        } catch (Exception e) {
            /**
             * accept all exception, include ClassNotFoundException,
             * NoSuchMethodException, InvocationTargetException,
             * NullPointException
             */
            e.printStackTrace();
        }
        return -1;
    }
 
    /**
     * resume download
     * 
     * @param ids
     *            the IDs of the downloads to be resumed
     * @return the number of downloads actually resumed, -1 if exception or
     *         method not exist
     */
    public int resumeDownload(long... ids) {
        initResumeMethod();
        if (resumeDownload == null) {
            return -1;
        }
 
        try {
            return ((Integer) resumeDownload.invoke(downloadManager, ids))
                    .intValue();
        } catch (Exception e) {
            /**
             * accept all exception, include ClassNotFoundException,
             * NoSuchMethodException, InvocationTargetException,
             * NullPointException
             */
            e.printStackTrace();
        }
        return -1;
    }
 
    /**
     * whether exist pauseDownload and resumeDownload method in
     * {@link DownloadManager}
     * 
     * @return
     */
    public static boolean isExistPauseAndResumeMethod() {
        initPauseMethod();
        initResumeMethod();
        return pauseDownload != null && resumeDownload != null;
    }
 
    private static void initPauseMethod() {
        if (isInitPauseDownload) {
            return;
        }
 
        isInitPauseDownload = true;
        try {
            pauseDownload = DownloadManager.class.getMethod(
                    METHOD_NAME_PAUSE_DOWNLOAD, long[].class);
        } catch (Exception e) {
            // accept all exception
            e.printStackTrace();
        }
    }
 
    private static void initResumeMethod() {
        if (isInitResumeDownload) {
            return;
        }
 
        isInitResumeDownload = true;
        try {
            resumeDownload = DownloadManager.class.getMethod(
                    METHOD_NAME_RESUME_DOWNLOAD, long[].class);
        } catch (Exception e) {
            // accept all exception
            e.printStackTrace();
        }
    }
 
    /**
     * get download file name
     * 
     * @param downloadId
     * @return
     */
    public String getFileName(long downloadId) {
        return getString(
                downloadId,
                (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ? COLUMN_LOCAL_URI
                        : COLUMN_LOCAL_FILENAME));
    }
 
    /**
     * get download uri
     * 
     * @param downloadId
     * @return
     */
    public String getUri(long downloadId) {
        return getString(downloadId, DownloadManager.COLUMN_URI);
    }
 
    /**
     * get failed code or paused reason
     * 
     * @param downloadId
     * @return <ul>
     *         <li>if status of downloadId is
     *         {@link DownloadManager#STATUS_PAUSED}, return
     *         {@link #getPausedReason(long)}</li>
     *         <li>if status of downloadId is
     *         {@link DownloadManager#STATUS_FAILED}, return
     *         {@link #getErrorCode(long)}</li>
     *         <li>if status of downloadId is neither
     *         {@link DownloadManager#STATUS_PAUSED} nor
     *         {@link DownloadManager#STATUS_FAILED}, return 0</li>
     *         </ul>
     */
    public int getReason(long downloadId) {
        return getInt(downloadId, DownloadManager.COLUMN_REASON);
    }
 
    /**
     * get paused reason
     * 
     * @param downloadId
     * @return <ul>
     *         <li>if status of downloadId is
     *         {@link DownloadManager#STATUS_PAUSED}, return one of
     *         {@link DownloadManager#PAUSED_WAITING_TO_RETRY}<br/>
     *         {@link DownloadManager#PAUSED_WAITING_FOR_NETWORK}<br/>
     *         {@link DownloadManager#PAUSED_QUEUED_FOR_WIFI}<br/>
     *         {@link DownloadManager#PAUSED_UNKNOWN}</li>
     *         <li>else return {@link DownloadManager#PAUSED_UNKNOWN}</li>
     *         </ul>
     */
    public int getPausedReason(long downloadId) {
        return getInt(downloadId, DownloadManager.COLUMN_REASON);
    }
 
    /**
     * get failed error code
     * 
     * @param downloadId
     * @return one of {@link DownloadManager#ERROR_*}
     */
    public int getErrorCode(long downloadId) {
        return getInt(downloadId, DownloadManager.COLUMN_REASON);
    }
 
    public static class RequestPro extends DownloadManager.Request {
 
        public static final String METHOD_NAME_SET_NOTI_CLASS = "setNotiClass";
        public static final String METHOD_NAME_SET_NOTI_EXTRAS = "setNotiExtras";
 
        private static boolean isInitNotiClass = false;
        private static boolean isInitNotiExtras = false;
 
        private static Method setNotiClass = null;
        private static Method setNotiExtras = null;
 
        /**
         * @param uri
         *            the HTTP URI to download.
         */
        public RequestPro(Uri uri) {
            super(uri);
        }
 
        /**
         * set noti class, only init once
         * 
         * @param className
         *            full class name
         */
        public void setNotiClass(String className) {
            synchronized (this) {
 
                if (!isInitNotiClass) {
                    isInitNotiClass = true;
                    try {
                        setNotiClass = Request.class.getMethod(
                                METHOD_NAME_SET_NOTI_CLASS, CharSequence.class);
                    } catch (Exception e) {
                        // accept all exception
                        e.printStackTrace();
                    }
                }
            }
 
            if (setNotiClass != null) {
                try {
                    setNotiClass.invoke(this, className);
                } catch (Exception e) {
                    /**
                     * accept all exception, include ClassNotFoundException,
                     * NoSuchMethodException, InvocationTargetException,
                     * NullPointException
                     */
                    e.printStackTrace();
                }
            }
        }
 
        /**
         * set noti extras, only init once
         * 
         * @param extras
         */
        public void setNotiExtras(String extras) {
            synchronized (this) {
 
                if (!isInitNotiExtras) {
                    isInitNotiExtras = true;
                    try {
                        setNotiExtras = Request.class
                                .getMethod(METHOD_NAME_SET_NOTI_EXTRAS,
                                        CharSequence.class);
                    } catch (Exception e) {
                        // accept all exception
                        e.printStackTrace();
                    }
                }
            }
 
            if (setNotiExtras != null) {
                try {
                    setNotiExtras.invoke(this, extras);
                } catch (Exception e) {
                    /**
                     * accept all exception, include ClassNotFoundException,
                     * NoSuchMethodException, InvocationTargetException,
                     * NullPointException
                     */
                    e.printStackTrace();
                }
            }
        }
    }
 
    /**
     * get string column
     * 
     * @param downloadId
     * @param columnName
     * @return
     */
    private String getString(long downloadId, String columnName) {
        DownloadManager.Query query = new DownloadManager.Query()
                .setFilterById(downloadId);
        String result = null;
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {
                result = c.getString(c.getColumnIndex(columnName));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return result;
    }
 
    /**
     * get int column
     * 
     * @param downloadId
     * @param columnName
     * @return
     */
    private int getInt(long downloadId, String columnName) {
        DownloadManager.Query query = new DownloadManager.Query()
                .setFilterById(downloadId);
        int result = -1;
        Cursor c = null;
        try {
            c = downloadManager.query(query);
            if (c != null && c.moveToFirst()) {
                result = c.getInt(c.getColumnIndex(columnName));
            }
        } finally {
            if (c != null) {
                c.close();
            }
        }
        return result;
    }
}

package com.example.download.utils;
 
import android.content.Context;
import android.content.SharedPreferences;
 
/**
 * PreferencesUtils, easy to get or put data
 */
public class PreferencesUtils {
 
    public static String PREFERENCE_NAME = "TrineaAndroidCommon";
 
    /**
     * put string preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to modify
     * @param value
     *            The new value for the preference
     * @return True if the new values were successfully written to persistent
     *         storage.
     */
    public static boolean putString(Context context, String key, String value) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(key, value);
        return editor.commit();
    }
 
    /**
     * get string preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @return The preference value if it exists, or null. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a string
     * @see #getString(Context, String, String)
     */
    public static String getString(Context context, String key) {
        return getString(context, key, null);
    }
 
    /**
     * get string preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @param defaultValue
     *            Value to return if this preference does not exist
     * @return The preference value if it exists, or defValue. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a string
     */
    public static String getString(Context context, String key,
            String defaultValue) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        return settings.getString(key, defaultValue);
    }
 
    /**
     * put int preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to modify
     * @param value
     *            The new value for the preference
     * @return True if the new values were successfully written to persistent
     *         storage.
     */
    public static boolean putInt(Context context, String key, int value) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        editor.putInt(key, value);
        return editor.commit();
    }
 
    /**
     * get int preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @return The preference value if it exists, or -1. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a int
     * @see #getInt(Context, String, int)
     */
    public static int getInt(Context context, String key) {
        return getInt(context, key, -1);
    }
 
    /**
     * get int preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @param defaultValue
     *            Value to return if this preference does not exist
     * @return The preference value if it exists, or defValue. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a int
     */
    public static int getInt(Context context, String key, int defaultValue) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        return settings.getInt(key, defaultValue);
    }
 
    /**
     * put long preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to modify
     * @param value
     *            The new value for the preference
     * @return True if the new values were successfully written to persistent
     *         storage.
     */
    public static boolean putLong(Context context, String key, long value) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        editor.putLong(key, value);
        return editor.commit();
    }
 
    /**
     * get long preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @return The preference value if it exists, or -1. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a long
     * @see #getLong(Context, String, long)
     */
    public static long getLong(Context context, String key) {
        return getLong(context, key, -1);
    }
 
    /**
     * get long preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @param defaultValue
     *            Value to return if this preference does not exist
     * @return The preference value if it exists, or defValue. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a long
     */
    public static long getLong(Context context, String key, long defaultValue) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        return settings.getLong(key, defaultValue);
    }
 
    /**
     * put float preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to modify
     * @param value
     *            The new value for the preference
     * @return True if the new values were successfully written to persistent
     *         storage.
     */
    public static boolean putFloat(Context context, String key, float value) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        editor.putFloat(key, value);
        return editor.commit();
    }
 
    /**
     * get float preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @return The preference value if it exists, or -1. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a float
     * @see #getFloat(Context, String, float)
     */
    public static float getFloat(Context context, String key) {
        return getFloat(context, key, -1);
    }
 
    /**
     * get float preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @param defaultValue
     *            Value to return if this preference does not exist
     * @return The preference value if it exists, or defValue. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a float
     */
    public static float getFloat(Context context, String key, float defaultValue) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        return settings.getFloat(key, defaultValue);
    }
 
    /**
     * put boolean preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to modify
     * @param value
     *            The new value for the preference
     * @return True if the new values were successfully written to persistent
     *         storage.
     */
    public static boolean putBoolean(Context context, String key, boolean value) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = settings.edit();
        editor.putBoolean(key, value);
        return editor.commit();
    }
 
    /**
     * get boolean preferences, default is false
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @return The preference value if it exists, or false. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a boolean
     * @see #getBoolean(Context, String, boolean)
     */
    public static boolean getBoolean(Context context, String key) {
        return getBoolean(context, key, false);
    }
 
    /**
     * get boolean preferences
     * 
     * @param context
     * @param key
     *            The name of the preference to retrieve
     * @param defaultValue
     *            Value to return if this preference does not exist
     * @return The preference value if it exists, or defValue. Throws
     *         ClassCastException if there is a preference with this name that
     *         is not a boolean
     */
    public static boolean getBoolean(Context context, String key,
            boolean defaultValue) {
        SharedPreferences settings = context.getSharedPreferences(
                PREFERENCE_NAME, Context.MODE_PRIVATE);
        return settings.getBoolean(key, defaultValue);
    }
}


参考资料


  • Trinea-common

其他精彩文章文章

在 android dialog中使用Autocompletetext 
大型网站架构设计-Solr
mysql哈希索引
android学习笔记(32)网格视图(GridView )和图形切换器(ImageSwi...
android学习笔记(31)可展开的列表组件(ExpandableListView )

更多关于android开发文章



Android 演示 DownloadManager 下载