DownLoad Manager 系统自带下载类 Jetpack

 一、 // 下载时,不显示通知栏
  downRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
因此在AndroidManifest.xml文件中加入上面所需要的权限即可。

<!--DownloadManager下载时不显示Notification-->
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />

二、9.0 如果访问http网址,记得加上

android:usesCleartextTraffic="true"

三、注册监听器ContentObserver(必须在执行下载前注册内容监听者)
三个参数分别是所要监听的Uri、false表示精确匹配此Uri,true表示可以匹配其派生的Uri、ContentObserver的派生类实例。


一、基础(粗粗看一下就行,看代码一下就知道怎样用)

  • DownloadManager简介
    DownloadManager是Android 2.3(API level 9)用系统服务(Service)的方式提供了DownloadManager来处理长时间的下载操作。它包含两个静态内部类DownloadManager.Query(用来查询下载信息)DownloadManager.Request(用来请求一个下载)
    DownloadManager主要提供了下面几个方法:
    public long enqueue(Request request)把任务加入下载队列并返回downloadId,以便后面用于查询下载信息。若网络不满足条件、Sdcard挂载中、超过最大并发数等异常会等待下载,正常则直接下载。
    public int remove(long… ids)删除下载,若取消下载,会同时删除下载文件和记录。
    public Cursor query(Query query)查询下载信息,包括下载文件总大小,已经下载的大小以及下载状态等。

  • ContentObserver简介
    public void ContentObserver(Handler handler) 所有ContentObserver的派生类都需要调用该构造方法,参数:handler Handler对象用于在主线程中修改UI。
    public void onChange(boolean selfChange)当观察到的Uri中内容发生变化时,就会回调该方法。所有ContentObserver的派生类都需要重载该方法去处理逻辑。
    观察特定Uri的步骤如下:
    1、创建我们特定的ContentObserver派生类,必须重载父类构造方法,必须重载onChange()方法去处理回调后的功能实现。
    2、为指定的Uri注册一个ContentObserver派生类实例,当给定的Uri发生改变时,回调该实例对象去处理,调用registerContentObserver()方法去注册内容观察者。
    3、由于ContentObserver的生命周期不同步于Activity和Service等。因此,在不需要时,需要手动的调用unregisterContentObserver()注销内容观察者。

二、通过广播接收者监听下载状态

public class DownUtils {
    private DownResultListener downResultListener=null;
    private static final String TAG = "DownUtils";
    //下载器
    private DownloadManager downloadManager=null;
    //下载的ID
    private long downloadId=-1;
    private String pathstr="";
    private boolean downingFlag=false;

    /**
     * 下载apk 每个实例,同一时间只可以有一个下载任务
     * @param mContext
     * @param url
     * @param downFileName 下载的文件名,要带后缀,例如:myjst.apk
     * @param showInNotify
     * @param notifyTitle
     * @param notifyMsg
     * @param listener
     * @return
     */
    public boolean downloadTask(Context mContext, String url, String downFileName,
                                boolean showInNotify, String notifyTitle, String notifyMsg, DownResultListener listener) {
        if(downingFlag){
            return false;
        }else{
            downingFlag=true;
        }
        downloadId=-1;
        this.downResultListener=listener;
        //创建下载任务
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        //移动网络情况下是否允许漫游
        request.setAllowedOverRoaming(false);
        // 设置通知是否显示
        if(showInNotify){
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        }else{
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
        }
        // <!--DownloadManager下载时不显示Notification--> 要加下面权限
        //<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
        //request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
        //设置下载中通知栏提示的标题
        request.setTitle(notifyTitle);
        //设置下载中通知栏提示的介绍
        request.setDescription(notifyMsg);
        request.setVisibleInDownloadsUi(true);
        // 通过setAllowedNetworkTypes方法可以设置允许在何种网络下下载,
        // 也可以使用setAllowedOverRoaming方法,它更加灵活
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        //request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
        // 文件类型
        //request.setMimeType("application/zip");
        //设置下载的路径
        File file = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), downFileName);
        request.setDestinationUri(Uri.fromFile(file));
        pathstr = file.getAbsolutePath();
        //request.setDestinationInExternalPublicDir("DownloadManagerTest", "myjst.apk");
        //获取DownloadManager
        if (downloadManager == null)
            downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        //将下载请求加入下载队列,加入下载队列后会给该任务返回一个long型的id,通过该id可以取消任务,重启任务、获取下载的文件等等
        if (downloadManager != null) {
            downloadId = downloadManager.enqueue(request);
        }else{
            downingFlag=false;
            return false;
        }

        //如果是普通的下载,可以在这里注册广播接收者
        //apk升级功能,如果是在通知栏后台下载 ,一般放在application中注册(注销)广播接收者
        //因为启动下载后,用户可能在app中的任意页面。
        //解决方法,
        // 1、在application中注册(注销)广播接收者
        // 2、下载apk任务的id=-1 保存为全局变量,如果为id==-1,监听器不做处理
        //注册广播接收者,监听下载状态
        mContext.registerReceiver(receiver,
                new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

        return true;
    }

    //广播监听下载的各个状态
    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(downloadId==-1){
                return;
            }
            checkStatus(context);
        }
    };

    //检查下载状态
    private void checkStatus(Context context) {
        DownloadManager.Query query = new DownloadManager.Query();
        //通过下载的id查找
        query.setFilterById(downloadId);
        Cursor cursor = downloadManager.query(query);
        if (cursor.moveToFirst()) {
            int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
            switch (status) {
                //下载暂停
                case DownloadManager.STATUS_PAUSED:
                    Log.e(TAG, "queryUri: STATUS_PAUSED");
                    break;
                //下载延迟
                case DownloadManager.STATUS_PENDING:
                    Log.e(TAG, "queryUri: STATUS_PENDING");
                    break;
                //正在下载
                case DownloadManager.STATUS_RUNNING:
                    Log.e(TAG, "queryUri: STATUS_RUNNING");
                    break;
                //下载完成
                case DownloadManager.STATUS_SUCCESSFUL:
                    Log.e(TAG, "queryUri: STATUS_SUCCESSFUL");
                    if(downResultListener!=null){
                        downResultListener.onSuccess(context,pathstr);
                        downResultListener=null;
                    }
                    downloadId=-1;
                    context.unregisterReceiver(receiver);
                    downingFlag=false;
                    break;
                //下载失败
                case DownloadManager.STATUS_FAILED:
                    Log.e(TAG, "queryUri: STATUS_FAILED");
                    if(downResultListener!=null){
                        downResultListener.onFail(context,"失败");
                        downResultListener=null;
                    }
                    downloadId=-1;
                    context.unregisterReceiver(receiver);
                    downingFlag=false;
                    break;
            }
        }
        cursor.close();
    }


    public interface DownResultListener{
        public void onSuccess(Context context,String filePath);
        public void onFail(Context context,String msg);
    }

}

调用方法:

 new DownUtils().downloadTask(this, PATH, "myjst.apk", true
                ,"title","msg des` ", new DownUtils.DownResultListener() {
                    @Override
                    public void onSuccess(Context context, String filePath) {
                        Tools.installAPK(context,new File(filePath));
                        Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFail(Context context, String msg) {
                        Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
                    }
                });



三、实时获取下载的进度。(这个demo只是练习,写得很粗糙,实战时要自行修改)

public class DownLoadActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final String PATH = "http://xxx/rch.apk";
    private long mId = -1;
    private DownloadManager mDownloadManager;
    private DownloadManager.Query mQuery;
    private Uri mUri;
    private Handler myHandler=new Handler();
    private DownloadStatusObserver observer = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_down_load);
        // 获取DownloadManager对象
        mDownloadManager = (DownloadManager) this.getSystemService(DOWNLOAD_SERVICE);
        observer = new DownloadStatusObserver(myHandler);
        //在执行下载前注册内容监听者
        registerContentObserver();
    }



    /**
     * 下载点击
     */
    public void downLoad(View view) {
        doSuccess=false;
        /* 移到onCreate
        // 获取DownloadManager对象
        mDownloadManager = (DownloadManager) this.getSystemService(DOWNLOAD_SERVICE);
        observer = new DownloadStatusObserver(myHandler);
        //在执行下载前注册内容监听者
        registerContentObserver();*/

        // 创建一个下载请求
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(PATH));
        // 设置内存卡保存的文件夹与文件名
        // setDestinationUri
        // setDestinationInExternalPublicDir
        request.setDestinationInExternalPublicDir("DownloadManagerTest", "myjst.apk");
        //设置下载中通知栏提示的标题
        request.setTitle("python");
        //设置下载中通知栏提示的介绍
        request.setDescription("python desc");
        // 设置通知是否显示
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        // 通过setAllowedNetworkTypes方法可以设置允许在何种网络下下载,
        // 也可以使用setAllowedOverRoaming方法,它更加灵活
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        request.setVisibleInDownloadsUi(true);
        // 文件类型
        request.setMimeType("application/zip");

        // 执行下载,返回downloadId,downloadId可用于后面查询下载信息。若网络不满足条件、Sdcard挂载中、超过最大并发数等异常会等待下载,正常则直接下载。
        mId = mDownloadManager.enqueue(request);
        // 返回移动网络下载的最大值
        Long maxBytesOverMobile = DownloadManager.getMaxBytesOverMobile(this);
        Log.e(TAG, "downLoad: maxBytesOverMobile ---------" + maxBytesOverMobile);
        // 获取建议的移动网络下载的大小
        Long recommendedMaxBytesOverMobile = DownloadManager.getRecommendedMaxBytesOverMobile(this);
        Log.e(TAG, "downLoad: recommendedMaxBytesOverMobile ---------" + recommendedMaxBytesOverMobile);


    }


    /**
     * 注册ContentObserver
     */
    private void registerContentObserver() {
        /** observer download change **/
        if (observer != null) {
            //三个参数分别是所要监听的Uri、false表示精确匹配此Uri,true表示可以匹配其派生的Uri、ContentObserver的派生类实例
            getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, observer);
        }
    }


    /**
     * 取消下载点击
     */
    public void unDownLoad(View view) {
        // 删除下载,若下载中取消下载。会同时删除下载文件和记录。
        mDownloadManager.remove(mId);
    }

    /**
     * 查询存储地址
     */
    public void queryUri(View view) {
        queryDownFileInfo();
    }

    private void queryDownFileInfo() {
        // 获取Uri和下载文件
        mUri = mDownloadManager.getUriForDownloadedFile(mId);
       /* if(mUri!=null){
            getContentResolver().unregisterContentObserver(observer);
            getContentResolver().registerContentObserver(mUri, true, observer);
        }*/
        Log.e(TAG, "queryUri: uri--------" + mUri);
        // 创建一个查询对象
        mQuery = new DownloadManager.Query().setFilterById(mId);
        // 根据查询对象获取一个游标对象
        Cursor cursor = mDownloadManager.query(mQuery);
        if (null != cursor) {
            if (cursor.moveToFirst()) {
                // 获取文件路径
                String fileUri = cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI));
                Log.e(TAG, "queryUri: fileUri ---------" + fileUri);
                // 获取下载状态
                int status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
                Log.e(TAG, "queryUri: " + status);
                logStatus(status);
            }
            cursor.close();
        }
    }

    /**
     * 获取下载信息
     *
     * @param downloadId 下载ID
     * @return
     */
    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 = mDownloadManager.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;
    }

    class DownloadStatusObserver extends ContentObserver {

        DownloadStatusObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            try {
                if(mId!=-1){
                    int[] bytesAndStatus = getBytesAndStatus(mId);
                    //当前大小
                    int currentSize = bytesAndStatus[0];
                    //总大小
                    int totalSize = bytesAndStatus[1];
                    //下载状态
                    int status = bytesAndStatus[2];
                    Log.e(TAG, "当前大小=" + currentSize + ",总大小=" + totalSize + ",status=" + status);
                    /*if(i++>100){
                        Log.e(TAG, "当前大小=" + currentSize + ",总大小=" + totalSize + ",status=" + status);
                        i=0;
                    }*/
                    //下载成功时,onChange的方法会调用多次,所以使用时要注意
                    logStatus(status);

                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }

    private boolean doSuccess=false;
    private void logStatus(int status) {
        switch (status) {
            // 空闲等待中
            case DownloadManager.STATUS_PENDING:
                Log.e(TAG, "queryUri: STATUS_PENDING");
                break;
            // 暂停中
            case DownloadManager.STATUS_PAUSED:
                Log.e(TAG, "queryUri: STATUS_PAUSED");
                break;
            // 正在下载
            case DownloadManager.STATUS_RUNNING:
                Log.e(TAG, "queryUri: STATUS_RUNNING");
                break;
            // 下载成功
            case DownloadManager.STATUS_SUCCESSFUL:
                Log.e(TAG, "queryUri: STATUS_SUCCESSFUL");
                if(!doSuccess){
                    doSuccess=true;
                    queryDownFileInfo();
                }

                break;
            // 下载失败
            case DownloadManager.STATUS_FAILED:
                Log.e(TAG, "queryUri: STATUS_FAILED");
                break;
            default:
                break;
        }
    }


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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getContentResolver().unregisterContentObserver(observer);
    }

    
}

xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
   >
    <Button
        android:onClick="downLoadfz"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载(封装方法)"/>

    <Button
        android:onClick="downLoad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载"/>

    <Button
        android:onClick="unDownLoad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="取消下载"/>

    <Button
        android:onClick="queryUri"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查询文件路径"/>

</LinearLayout>


 

参考文章:

1、Android DownLoadManager 使用 ,例子有bug

2、DownloadManager实现版本更新,监听下载进度

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值