美文网首页Android开发感悟Android学习知识Android开发
Android快速实现文件下载(只有4行代码)

Android快速实现文件下载(只有4行代码)

作者: Marno | 来源:发表于2016-06-24 10:47 被阅读35912次
    • 本文为 Marno 原创,转载必须保留出处!
    • 公众号【 aMarno 】,关注后回复 RN 加入交流群
    • React Native 优秀开源项目大全:http://www.marno.cn

    写在前面的废话

    下载文件,几乎是所有APP都会用到的功能!算了,还是不废话了,直接开写吧。。。

    简单使用

    完成一个下载任务只需要4行代码,什么断点续传,大文件下载,通知栏进度显示....都不需要你操心。

    //创建下载任务,downloadUrl就是下载链接
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
    //指定下载路径和下载文件名
    request.setDestinationInExternalPublicDir("/download/", fileName);
    //获取下载管理器
    DownloadManager downloadManager= (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
    //将下载任务加入下载队列,否则不会进行下载
    downloadManager.enqueue(request);
    
    高级用法
    • 通过上面的代码大家也看出来了,我们使用的是系统提供的下载管理器进行下载,从API 9就开始支持了,所以不用担心在兼容问题
    • 既然是系统提供的,那么肯定还有更加强大的用法,文章继续

    让我们看DownloadManager的源码,提供了这么多方法


    DownloadManager的方法
    DownloadManager.Request的方法
    • 方法差不多就这些,已经比较全了,可以满足我们绝大部分的使用场景。
    实际使用

    接下来我们就以APP应用内更新为例,讲一下这些方法的使用
    1.首先我们梳理下APP应用内更新的逻辑


    APP应用内更新

    2.接下来看具体实现,上代码

    //使用系统下载器下载
    private void downloadAPK(String versionUrl, String versionName) {
            //创建下载任务
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(versionUrl));
            request.setAllowedOverRoaming(false);//漫游网络是否可以下载
    
            //设置文件类型,可以在下载结束后自动打开该文件
            MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
            String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(versionUrl));
            request.setMimeType(mimeString);
    
            //在通知栏中显示,默认就是显示的
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
            request.setVisibleInDownloadsUi(true);
    
            //sdcard的目录下的download文件夹,必须设置
            request.setDestinationInExternalPublicDir("/download/", versionName);
            //request.setDestinationInExternalFilesDir(),也可以自己制定下载路径
    
            //将下载请求加入下载队列
            downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
            //加入下载队列后会给该任务返回一个long型的id,
            //通过该id可以取消任务,重启任务等等,看上面源码中框起来的方法
            mTaskId = downloadManager.enqueue(request);
    
            //注册广播接收者,监听下载状态
            mContext.registerReceiver(receiver,
                    new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
        }
    

    接下来是广播接收器

        //广播接受者,接收下载状态
        private BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                checkDownloadStatus();//检查下载状态
            }
        };
    

    检查下载状态

     //检查下载状态
        private void checkDownloadStatus() {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(mTaskId);//筛选下载任务,传入任务ID,可变参数
            Cursor c = downloadManager.query(query);
            if (c.moveToFirst()) {
                int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
                switch (status) {
                    case DownloadManager.STATUS_PAUSED:
                        MLog.i(">>>下载暂停");
                    case DownloadManager.STATUS_PENDING:
                        MLog.i(">>>下载延迟");
                    case DownloadManager.STATUS_RUNNING:
                        MLog.i(">>>正在下载");
                        break;
                    case DownloadManager.STATUS_SUCCESSFUL
                        MLog.i(">>>下载完成");
                        //下载完成安装APK
                        //downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + File.separator + versionName;
                        installAPK(new File(downloadPath));
                        break;
                    case DownloadManager.STATUS_FAILED:
                        MLog.i(">>>下载失败");
                        break;
                }
            }
        }
    

    安装APK

        //下载到本地后执行安装
        protected void installAPK(File file) {
            if (!file.exists()) return;
            Intent intent = new Intent(Intent.ACTION_VIEW);
            Uri uri = Uri.parse("file://" + file.toString());
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
            //在服务中开启activity必须设置flag,后面解释
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mContext.startActivity(intent);
        }
    

    到此就完成了应用内更新APP的代码,但是有一些坑需要注意!

    希望你可以看到最后这几句,不然你也会被坑的!

    1.虽然下载什么的不需要自己操心了,但是建议还是将整个上面四段代码放在Service中执行,因为放在Activity中时,当用户按home键后,即使下载完了,也不会弹出安装界面
    2.建议使用startService的方式启动Service,这样不会与Activity生命周期绑定,保证下载完后能顺利安装。
    3.Service使用完后要及时地停掉!


    相关文章

      网友评论

      • GameProgramer:downloadmanager并不能通用,在某些品牌手机上不行,不信你可以写个demo提交到云测,看结果,所以还是老老实实自己写一个服务来下载最好
        各位看官看看这个吧
        https://github.com/YoungBill/RetrofitDownloadManager
      • zero_4e7b:支持线程池管理、断点续传、下载完成校验、下载过程中断、下载文件名MD5化(TaskEntity build时可选择是否使用)
        https://github.com/zerochl/ClassicDownload
      • 求知好学:我试了下 的确可以用 谢谢 你的分享精神
      • 南京空白:太赞了
      • Passenger_3b23:(String versionUrl, String versionName)传的不是检测有没新版的地址吗 怎么变成下载地址了?
      • Ken_mmm:为什么下载下来的 apk 大小和你本地的大小不一样...
      • ea841a007e1c:registerReceiver(receiver,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); 貌似只能监听到 下载完成啊,其他状态没有打印
        道梦鱼:你在线程里写个循环,定时调用checkDownloadStatus()就好,下载完成就跳出循环。
      • 86f1c35340a8:看看这里,有解决方法,高逼格超简单http://blog.csdn.net/shan_yao/article/details/51881913
      • 86c8d59b7b96:膜拜大神 可以的
      • 540c229b9e69:downloadmanager并不能通用,在某些品牌手机上不行,不信你可以写个demo提交到云测,看结果,所以还是老老实实自己写一个服务来下载最好
      • hunter886:DownloadManager 在某些型号的手机上会被禁掉,有解决方案吗?
        86f1c35340a8:看看这里,有解决方法,高逼格超简单http://blog.csdn.net/shan_yao/article/details/51881913
        hunter886:@Marno 三星Note系列的手机大多数会被禁用,但是可以在设置中打开。还有一些国产手机会把这个功能阉割掉,或者用户可以卸载掉DownloadManager这个程序。
        Marno: @ovwvwvo 公司的测试机目前没有出现被禁用的情况,你说的是哪一款手机呢?
      • ad8d35b077ef:我下载的文件在安装的时候,出现解析程序包错误,请问下是什么原因!
        ad8d35b077ef:@爱在蔓延中 恩,可以了,下载路径跟安装路径没有一致!
        爱在蔓延中:@ad8d35b077ef 有可能是断点续传的问题, 下载的文件不完整
      • peerless2012:试试快速重复下载又想避免重复下载,就会发现坑了
        7cd0f85bfcce:@peerless2016 华为P6 点击就奔溃 其它手机暂无发现。
        Marno:@peerless2016 其实每个工具都有其使用场景,如果对”下载功能“依赖程度非常高,比如迅雷这类软件,那这个方法肯定就不适合了,还是需要自己实现下载过程。
        HustFox:@peerless2016 能说具体点儿么?
      • 8ec9bd387d5b:刚好需要用到,写的太好了,谢谢分享

      本文标题:Android快速实现文件下载(只有4行代码)

      本文链接:https://www.haomeiwen.com/subject/mteodttx.html