网络通信——下载管理器DownloadManager——在通知栏显示下载进度

尽管直接使用GET方式也能下载网络文件,但这种方式存在以下缺点:

(1)无法断点续传,一旦中途失败,只能从头开始获取。(2)不是真正意义上的下载操作,没法设置下载参数。(3)下载过程中无法在界面上展示下载状态。

================================================================================================

布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="请选择要下载的安装包:"
            android:textColor="@color/black"
            android:textSize="17sp" />

        <Spinner
            android:id="@+id/sp_apk_url"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:spinnerMode="dialog" />
    </LinearLayout>

    <TextView
        android:id="@+id/tv_apk_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="17sp" />

</LinearLayout>

ApkConstant
package com.example.myapplication.constant;

import com.example.myapplication.R;

public class ApkConstant {
    public static String[] NAME_ARRAY = {
            "爱奇艺", "酷狗音乐", "美图秀秀", "微信", "淘宝", "QQ"
    };
    public static String[] PACKAGE_ARRAY = {
            "com.qiyi.video", "com.kugou.android", "com.mt.mtxx.mtxx",
            "com.tencent.mm", "com.taobao.taobao", "com.tencent.mobileqq"
    };
    public static int[] ICON_ARRAY = {
            R.drawable.icon_aiqiyi, R.drawable.icon_kugou, R.drawable.icon_meitu,
            R.drawable.icon_weixin, R.drawable.icon_taobao, R.drawable.icon_qq
    };
    public static String[] URL_ARRAY = {
            "http://103.231.68.98/McDonald/e/6880639/0/0/0/1632195714369/package_800120950.1632195714369&#39",
            "http://103.231.68.98/McDonald/e/6881873/0/0/0/1632195604939/package_10849.1632195604939&#39",
            "http://103.231.68.98/McDonald/e/6884026/0/0/0/1632196015129/package_9290.1632196015129&#39",
            "http://103.231.68.98/McDonald/e/6882606/0/0/0/1632197046375/package_17857.1632197046375&#39",
            "http://103.231.68.98/McDonald/e/6879467/0/0/0/1632194248559/package_1902.1632194248559&#39",
            "http://103.231.68.98/McDonald/e/6883576/0/0/0/1632196869079/package_2092.1632196869079&#39"
    };

}

DateUtil
package com.example.myapplication.util;

import android.annotation.SuppressLint;
import android.text.TextUtils;

import java.text.SimpleDateFormat;
import java.util.Date;

@SuppressLint("SimpleDateFormat")
public class DateUtil {
    // 获取当前的日期时间
    public static String getNowDateTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(new Date());
    }

    // 获取当前的时间
    public static String getNowTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(new Date());
    }

    // 获取当前的时间(精确到毫秒)
    public static String getNowTimeDetail() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
        return sdf.format(new Date());
    }

    // 获取指定格式的日期时间
    public static String getNowDateTime(String formatStr) {
        String format = formatStr;
        if (TextUtils.isEmpty(format)) {
            format = "yyyyMMddHHmmss";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date());
    }

    public static String formatDate(long time) {
        Date date = new Date(time);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    // 重新格式化日期字符串
    public static String convertDateString(String strTime) {
        String newTime = strTime;
        try {
            SimpleDateFormat oldFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            Date date = oldFormat.parse(strTime);
            SimpleDateFormat newFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            newTime = newFormat.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newTime;
    }

}
MainActivity
package com.example.myapplication;

import android.annotation.SuppressLint;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

import com.example.myapplication.constant.ApkConstant;

import com.example.myapplication.util.DateUtil;

@SuppressLint({"SetTextI18n","DefaultLocale"})
public class MainActivity extends AppCompatActivity
{

    private static final String TAG = "DownloadApkActivity";
    private Spinner sp_apk_url; // 安装包链接的下拉框
    private TextView tv_apk_result;
    private boolean isFirstSelect = true; // 是否首次选择
    private DownloadManager mDownloadManager; // 声明一个下载管理器对象
    private long mDownloadId = 0; // 下载编号

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv_apk_result = findViewById(R.id.tv_apk_result);

        // 从系统服务中获取下载管理器
        mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

        initApkSpinner(); // 初始化安装包链接的下拉框
    }

    // 初始化安装包链接的下拉框
    private void initApkSpinner()
    {
        ArrayAdapter<String> apkUrlAdapter = new ArrayAdapter<String>(this, R.layout.item_select, ApkConstant.NAME_ARRAY);

        sp_apk_url = findViewById(R.id.sp_apk_url);

        sp_apk_url.setPrompt("请选择要下载的安装包");

        sp_apk_url.setAdapter(apkUrlAdapter);

        sp_apk_url.setOnItemSelectedListener(new ApkUrlSelectedListener());

        sp_apk_url.setSelection(0);
    }

    class ApkUrlSelectedListener implements OnItemSelectedListener
    {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3)
        {

            if (isFirstSelect)      // 刚打开页面时不需要执行下载动作
            {

                isFirstSelect = false;
                return;
            }
            startDownload(arg2); // 开始下载指定序号的apk文件
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

    // 开始下载指定序号的apk文件
    private void startDownload(int pos)
    {

        tv_apk_result.setText("正在下载" + ApkConstant.NAME_ARRAY[pos] + "的安装包,请到通知栏查看下载进度");

        Uri uri = Uri.parse(ApkConstant.URL_ARRAY[pos]); // 根据下载地址构建一个Uri对象

        Request down = new Request(uri); // 创建一个下载请求对象,指定从哪里下载文件

        down.setTitle(ApkConstant.NAME_ARRAY[pos] + "下载信息"); // 设置任务标题

        down.setDescription(ApkConstant.NAME_ARRAY[pos] + "安装包正在下载"); // 设置任务描述

        // 设置允许下载的网络类型
        down.setAllowedNetworkTypes(Request.NETWORK_MOBILE | Request.NETWORK_WIFI);

        // 设置通知栏在下载进行时与完成后都可见
        down.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

        // 设置下载文件在私有目录的保存路径。从Android10开始,只有保存到公共目录的才会在系统下载页面显示,保存到私有目录的不在系统下载页面显示
        down.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, pos + ".apk");

        // 设置下载文件在公共目录的保存路径。保存到公共目录需要申请存储卡的读写权限
        //down.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, pos + ".apk");
        mDownloadId = mDownloadManager.enqueue(down); // 把下载请求对象加入到下载队列
    }

    // 定义一个下载完成的广播接收器。用于接收下载完成事件
    private class DownloadCompleteReceiver extends BroadcastReceiver
    {

        @Override
        public void onReceive(Context context, Intent intent)
        {

            if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE))   // 下载完毕
            {

                // 从意图中解包获得下载编号
                long downId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

                Log.d(TAG, "下载完成 id : " + downId + ", mDownloadId=" + mDownloadId);

                tv_apk_result.setVisibility(View.VISIBLE);

                String desc = String.format("%s 编号%d的下载任务已完成", DateUtil.getNowTime(), downId);

                tv_apk_result.setText(desc); // 显示下载任务的完成描述
            }
        }
    }

    // 定义一个通知栏点击的广播接收器。用于接收下载通知栏的点击事件,在下载过程中有效,下载完成后失效
    private class NotificationClickReceiver extends BroadcastReceiver
    {

        @Override
        public void onReceive(Context context, Intent intent)
        {

            if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED))  // 点击了通知栏
            {
                // 从意图中解包获得被点击通知的下载编号
                long[] downIds = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);

                for (long downId : downIds)
                {

                    Log.d(TAG, "点击通知 id : " + downId + ", mDownloadId=" + mDownloadId);

                    if (downId == mDownloadId)   // 找到当前的下载任务
                    {
                        String desc = String.format("%s 点击了编号%d的下载通知", DateUtil.getNowTime(), downId);

                        tv_apk_result.setText(desc); // 显示下载任务的点击描述
                    }
                }
            }
        }
    }

    private DownloadCompleteReceiver completeReceiver; // 声明一个下载完成的广播接收器

    private NotificationClickReceiver clickReceiver; // 声明一个通知栏点击的广播接收器

    @Override
    public void onStart()
    {

        super.onStart();


        completeReceiver = new DownloadCompleteReceiver(); // 创建一个下载完成的广播接收器

        // 注册接收器,注册之后才能正常接收广播
        registerReceiver(completeReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

        clickReceiver = new NotificationClickReceiver(); // 创建一个通知栏点击的广播接收器

        // 注册接收器,注册之后才能正常接收广播
        registerReceiver(clickReceiver, new IntentFilter(DownloadManager.ACTION_NOTIFICATION_CLICKED));
    }

    @Override
    public void onStop()
    {

        super.onStop();


        unregisterReceiver(completeReceiver); // 注销下载完成的广播接收器

        unregisterReceiver(clickReceiver); // 注销通知栏点击的广播接收器
    }

}

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值