Android DownloadManager 使用

1. 概述

        DownloadManager是一个可以处理长时间运行的HTTP下载的系统服务,客户端请求一个URL地址去下载一个目标文件, 下载管理器将在后台进行下载,处理HTTP交互,并在失败或连接更改和系统重新启动后重试下载。

        如果APP通过DownloadManager请求下载,那么应用注ACTION_NOTIFICATION_CLICKED的广播,以便在用户单击下载通知栏或者下载UI时,进行适当处理。

        如果要使用DownloadManager, 必须要申请Manifest.permission.INTERNET权限。

        它是安卓系统默认的下载管理器,最终也是通过HttpURLConnection去实现下载任务的。

2. API介绍

        DownLoadManager有两个内部类,Request用于封装一个下载请求,Query则用于封装一个查询请求。

2.1  Request方法说明

方法说明
public Request setTitle(CharSequence title)设置下载通知的标题
public Request setDescription(CharSequence description)设置下载通知的描述信息
public Request setAllowedNetworkTypes(int flags)
指定在某种网络环境下,进行下载文件
DownloadManager.Request.NETWORK_WIFI:wifi环境
DownloadManager.Request.NETWORK_MOBILE:手机网络环境
public Request setAllowedOverRoaming(boolean allowed)是否允许漫游
public Request setVisibleInDownloadsUi(boolean isVisible)
下载情况是否显示在systemUI下拉状态栏中
public Request setNotificationVisibility(int visibility)
可以设置如下四个值:
1. VISIBILITY_HIDDEN 下载UI不会显示,也不会显示在通知中,如果设置该值,需要声明android.permission.DOWNLOAD_WITHOUT_NOTIFICATION

2. VISIBILITY_VISIBLE 当处于下载中状态时,可以在通知栏中显示;当下载完成后,通知栏中不显示

3. VISIBILITY_VISIBLE_NOTIFY_COMPLETED 当处于下载中状态和下载完成时状态,均在通知栏中显示

4. VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION 只在下载完成时显示在通知栏中。
public void allowScanningByMediaScanner()
设置为可被媒体扫描器找到
public long enqueue(Request request) 
加入到下载的队列中。一旦下载管理器准备好执行并且连接可用,下载将自动启动。
返回一个下载任务对应唯ID, 此id可以用来去查询下载内容的相关信息

下载存放路径区别:

public Request setDestinationInExternalPublicDir(String dirType, String subPath)

setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "QQ.apk");

//下载路径为 sdcard/download/QQ.apk

 如果下载的文件希望被其他的应用共享, 特别是那些你下载下来希望被Media Scanner扫描到的文件(比如音乐文件)就可以通过如下方法设置:

setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC,  "简单爱.mp3" );

//下载路径为:  sdcard/Music/简单爱.mp3

 public Request setDestinationInExternalFilesDir(Context context, String dirType, String subPath)

该方法适用此场景:这个文件是你的应用所专用的,软件卸载后,下载的文件将随着卸载全部被删除

setDestinationInExternalFilesDir(this , Environment.DIRECTORY_DOWNLOADS ,"QQ.apk");
//下载路径为: Android/data/com.app.xx/files/Download/QQ.apk

2.2  Query方法说明

方法说明
public Query setFilterById(long... ids)
通过下载ID获取Query对象
public Cursor query(Query query)
该方法返回一个Cursor对象,具体需要查询哪个字段可以查看DownloadManager的以COLUM_**开头的常量

        当需要查询下载进度或状态时,可以创建DownloadManager.Query对象,然后再调用DownloadManager.query方法进行查询,该方法返回一个Cursor对象,具体需要查询哪个字段可以查看DownloadManager的以COLUM_**开头的常量, 创建Query对象后,可以根据id或者下载状态设置过滤条件。

2.3  取消任务

方法说明
public int remove(long... ids)
用于删除下载,如果下载中则取消下载, 同时会删除下载文件和记录

2.4 广播监听

1.  DownloadManager.ACTION_DOWNLOAD_COMPLETE  

        当任务下载完成之后,系统会发送这个广播

2. DownloadManager.ACTION_NOTIFICATION_CLICKED

        当点击通知栏中的下载栏时,系统会发送这个广播

我们可以根据需求在里面做对应的逻辑处理。

3. 业务需求

        通过DownloadManager通过网络请求下载QQ.apk 的例子来讲解,代码逻辑比较简单,也做了注释,直接看代码即可

MainActivity.java 主要是处理广播注册,UI更新显示,下载任务  取消任务等操作

public class MainActivity extends Activity {

    private DownloadManager downloadManager;

    private DownloadManager.Query query;

    private DownloadTest mDownloadTest;


    private Timer mTimer;

    //下载任务的id
    private long mDownloadId;
    private TextView download;
    private TextView progressTxt;
    private ProgressBar pb_update;
    private Button mCancleBtn;

    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                Toast.makeText(MainActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
                try {
                    //跳转到显示下载内容的activity界面
                    Intent dm = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
                    dm.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(dm);
                } catch (ActivityNotFoundException ex){
                    Log.d("down",  "no activity for " + ex.getMessage());
                }
            } else if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
                Toast.makeText(MainActivity.this, "用户点击了通知栏", Toast.LENGTH_SHORT).show();
            }
        }
    };


    Handler handler =new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle bundle = msg.getData();
            int pro = bundle.getInt("progressMsg");
            pb_update.setProgress(pro);
            progressTxt.setText("下载进度:" + pro + "%");
        }
    };

    private TimerTask mTimerTask = new TimerTask() {
        @Override
        public void run() {
            Cursor cursor = downloadManager.query(query.setFilterById(mDownloadId));

            if (cursor != null && cursor.moveToFirst()) {
                int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
                Log.d("down", "status:" + status);
                switch (status) {
                    //下载暂停
                    case DownloadManager.STATUS_PAUSED:
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                download.setText("下载暂停");
                            }
                        });
                        break;
                    //下载延迟
                    case DownloadManager.STATUS_PENDING:
                        Log.e("down", "====下载延迟=====");
                        break;
                    //正在下载
                    case DownloadManager.STATUS_RUNNING:
                        //Log.e("down", "====正在下载中=====");
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                download.setText("正在下载中......");
                            }
                        });
                        break;
                    //下载完成
                    case DownloadManager.STATUS_SUCCESSFUL:
                        //下载完成安装APK
                        //Log.e("down", "====下载完成=====");
                        mTimerTask.cancel();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                pb_update.setProgress(100);
                                download.setText("下载完成");
                            }
                        });
                        break;
                    //下载失败
                    case DownloadManager.STATUS_FAILED:
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(MainActivity.this, "下载失败", Toast.LENGTH_LONG).show();
                            }
                        });
                        break;
                }


                long bytesDownload = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                String descrition = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION));
                String id = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_ID));
                String localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                String mimeType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE));
                String title = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE));
                long totalSize = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

                Log.d("down", "bytesDownload:" + bytesDownload);
                Log.d("down", "totalSize:" + totalSize);

                int progress = (int)(bytesDownload*100/totalSize) ;
                Message msg = Message.obtain();
                Bundle bundle = new Bundle();
                bundle.putInt("progressMsg", progress);
                msg.setData(bundle);
                handler.sendMessage(msg);
            }
            cursor.close();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        download = findViewById(R.id.down);
        progressTxt = findViewById(R.id.progress);
        pb_update = findViewById(R.id.pb_update);
        mCancleBtn = findViewById(R.id.cancle_down);


        downloadManager = (DownloadManager)this.getSystemService(Context.DOWNLOAD_SERVICE);
        query = new DownloadManager.Query();
        mDownloadTest = new DownloadTest(this);

        //定时器
        mTimer = new Timer();

        //注册广播,监听下载状态
        IntentFilter intentfilter = new IntentFilter();
        intentfilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
        intentfilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
        registerReceiver(receiver, intentfilter);
    }


    @Override
    protected void onResume() {
        super.onResume();

        download.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mDownloadId =  mDownloadTest.downloadAPK("https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk", downloadManager);
                mTimer.schedule(mTimerTask, 0,1000);
                download.setEnabled(false);
            }
        });

        mCancleBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                downloadManager.remove(mDownloadId);
                download.setText("立即下载");
            }
        });
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mTimer != null) {
            mTimer.cancel();
        }
        if (mTimerTask != null) {
            mTimerTask.cancel();
        }
        handler.removeCallbacksAndMessages(null);
        unregisterReceiver(receiver);
    }
}
DownloadTest.java 是下载请求类: 封装了request对象, 然后enqueue(request)开始下载任务,返回任务的唯一ID号, 供查询下载任务API调用。
public class DownloadTest {
    private Context mContext;

    public DownloadTest(Context context) {
        mContext = context;
    }

    public long downloadAPK(String downloadurl, DownloadManager downloadManager) {
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadurl));

        //设置Notifcaiton的标题和描述
        request.setTitle("QQ.apk");
        request.setDescription("最新1.5.1版本下载中.....");

        //指定在WIFI状态下,执行下载操作。
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        //指定在MOBILE状态下,执行下载操作
        //request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE);
        //移动网络情况下是否允许漫游
        request.setAllowedOverRoaming(false);
        //下载情况是否显示在systemUI下拉状态栏中
        request.setVisibleInDownloadsUi(true);

        //设置Notification的显示,和隐藏
        /*
        在下载进行中时显示,在下载完成后就不显示了。可以设置如下三个值:
        VISIBILITY_HIDDEN 下载UI不会显示,也不会显示在通知中,如果设置该值,需要声明android.permission.DOWNLOAD_WITHOUT_NOTIFICATION
        VISIBILITY_VISIBLE 当处于下载中状态时,可以在通知栏中显示;当下载完成后,通知栏中不显示
        VISIBILITY_VISIBLE_NOTIFY_COMPLETED 当处于下载中状态和下载完成时状态,均在通知栏中显示
        VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION 只在下载完成时显示在通知栏中。
        * */
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

        //设置为可被媒体扫描器找到
        request.allowScanningByMediaScanner();

        //设置下载路径 sdcard/download/
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "QQ.apk");

        //加入到下载的队列中。一旦下载管理器准备好执行并且连接可用,下载将自动启动。
        //一个下载任务对应唯一个ID, 此id可以用来去查询下载内容的相关信息
        long downloadID = downloadManager.enqueue(request);

        return downloadID;
    }
}

4. 效果图

展示效果图: 只录制了点击下载和取消下载的操作视频

 

其他在状态栏点击动作请下载Demo后操作

Demo下载地址: https://download.csdn.net/download/u012514113/86869148

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值