网络通信——下载管理器DownloadManager——主动轮询当前的下载进度

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

 

 

 

 

 

 

 

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.myapplication">

    <!-- 互联网 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 定位 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- 存储卡读写 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!-- 下载时不提示通知栏 -->
    <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />


    <!-- 下载时不提示通知栏 -->
    <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />

    <!-- 相机 -->
    <uses-permission android:name="android.permission.CAMERA" />
    <!-- 录音 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!-- 存储卡读写 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication"
        android:usesCleartextTraffic="true"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity7"
            android:exported="false" />
        <activity
            android:name=".MainActivity6"
            android:exported="false" />
        <activity
            android:name=".MainActivity5"
            android:exported="false"
            android:label="@string/title_activity_main5" />
        <activity
            android:name=".MainActivity4"
            android:exported="false"
            android:label="@string/title_activity_main4" />
        <activity
            android:name=".MainActivity3"
            android:exported="false"
            android:label="@string/title_activity_main3" />
        <activity
            android:name=".MainActivity2"
            android:exported="false"
            android:label="@string/title_activity_main2" />
        <activity
            android:name=".MainActivity"
            android:exported="true">

            <!-- android:theme="@style/AppCompatTheme" /> -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

布局:

<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">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <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_image_url"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:spinnerMode="dialog" />
            </LinearLayout>

            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <ImageView
                    android:id="@+id/iv_image_url"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/downloading"
                    android:scaleType="fitCenter" />

                <com.example.myapplication.widget.TextProgressCircle
                    android:id="@+id/tpc_progress"
                    android:layout_width="match_parent"
                    android:layout_height="350dp"
                    android:layout_gravity="center"
                    android:background="#99ffffff"
                    android:visibility="invisible" />
            </FrameLayout>

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

        </LinearLayout>
    </ScrollView>

</LinearLayout>

 

 

 

 

 

 

 

 

 

 

TextProgressCircle
package com.example.myapplication.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import com.example.myapplication.util.Utils;

@SuppressLint("DrawAllocation")
public class TextProgressCircle extends View {
    private Context mContext; // 声明一个上下文对象
    private Paint mPaintBack = new Paint(); // 声明一个背景画笔对象
    private Paint mPaintFore = new Paint(); // 声明一个前景画笔对象
    private Paint mPaintText = new Paint(); // 声明一个文本画笔对象
    private int mLineWidth; // 线条的宽度
    private int mProgress = 0; // 进度值

    public TextProgressCircle(Context context) {
        this(context, null);
    }

    public TextProgressCircle(Context context, AttributeSet attr) {
        super(context, attr);
        mContext = context;
        initPaint(); // 初始化画笔
    }

    // 初始化画笔
    private void initPaint() {
        mLineWidth = Utils.dip2px(mContext, 10);
        // 以下初始化背景画笔
        mPaintBack.setColor(Color.LTGRAY);
        mPaintBack.setStrokeWidth(mLineWidth);
        mPaintBack.setStyle(Style.STROKE);
        // 以下初始化前景画笔
        mPaintFore.setColor(Color.GREEN);
        mPaintFore.setStrokeWidth(mLineWidth);
        mPaintFore.setStyle(Style.STROKE);
        // 以下初始化文本画笔
        mPaintText.setColor(Color.BLUE);
        mPaintText.setTextSize(Utils.dip2px(mContext, 50));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getMeasuredWidth(); // 获得视图测量后的宽度
        int height = getMeasuredHeight(); // 获得视图测量后的高度
        int diameter = Math.min(width, height); // 宽度和高度取较小的那个作为进度圆圈的直径
        RectF rectF = new RectF((width - diameter) / 2 + mLineWidth, (height - diameter) / 2 + mLineWidth,
                (width + diameter) / 2 - mLineWidth, (height + diameter) / 2 - mLineWidth);
        // 在画布上绘制完整的背景圆圈
        canvas.drawArc(rectF, 0, 360, false, mPaintBack);
        // 在画布上绘制规定进度的前景圆弧
        canvas.drawArc(rectF, 0, mProgress * 360 / 100, false, mPaintFore);
        String text = mProgress + "%";
        Rect rect = new Rect();
        mPaintText.getTextBounds(text, 0, text.length(), rect); // 获得进度文字的矩形边界
        int x = (width / 2) - rect.centerX(); // 计算进度文字左上角的横坐标
        int y = (height / 2) - rect.centerY(); // 计算进度文字左上角的纵坐标
        canvas.drawText(text, x, y, mPaintText); // 在画布上绘制进度文字
    }

    // 设置进度值
    public void setProgress(int progress) {
        mProgress = progress;
        invalidate(); // 立刻刷新视图
    }

}

 

 

 

 

 

 

 

 

MainActivity
package com.example.myapplication;

import android.annotation.SuppressLint;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.myapplication.widget.TextProgressCircle;

import java.util.HashMap;

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

    private Spinner sp_image_url; // 图片链接的下拉框
    private ImageView iv_image_url;
    private TextProgressCircle tpc_progress; // 定义一个文本进度圈对象
    private TextView tv_image_result;
    private boolean isFirstSelect = true; // 是否首次选择
    private Uri mImageUri; // 图片的路径对象
    private DownloadManager mDownloadManager; // 声明一个下载管理器对象
    private long mDownloadId = 0; // 当前任务的下载编号
    private static HashMap<Integer, String> mStatusMap = new HashMap<Integer, String>(); // 下载状态映射
    static { // 初始化下载状态映射
        mStatusMap.put(DownloadManager.STATUS_PENDING, "挂起");
        mStatusMap.put(DownloadManager.STATUS_RUNNING, "运行中");
        mStatusMap.put(DownloadManager.STATUS_PAUSED, "暂停");
        mStatusMap.put(DownloadManager.STATUS_SUCCESSFUL, "成功");
        mStatusMap.put(DownloadManager.STATUS_FAILED, "失败");
    }
    private String[] imageDescArray = {
            "洱海公园", "丹凤亭", "宛在堂", "满庭芳", "玉带桥", "眺望洱海", "洱海女儿", "海心亭", "洱海岸边", "烟波浩渺"
    };
    private String[] imageUrlArray = {
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/nYJcslMIrGeDrujE5KZF2xBW8rjXMIVetZfrOAlSamM!/b/dPwxB5iaEQAA",
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/Adcl9XVS.RBED4D8shjceYHOhhR*6mcNyCcq24kJG2k!/b/dPwxB5iYEQAA",
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/bg*X6nT03YUReoJ97ked266WlWG3IzLjBdwHpKqkhYY!/b/dOg5CpjZEAAA",
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/JOPAKl9BO1wragCEIVzXLlHwj83qVhb8uNuHdmVRwP4!/b/dPwxB5iSEQAA",
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/7hHOgBEOBshH*7YAUx7RP0JzPuxRBD727mblw9TObhc!/b/dG4WB5i2EgAA",
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/m4Rjx20D9iFL0D5emuYqMMDji*HGQ2w2BWqv0zK*tRk!/b/dGp**5dYEAAA",
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/swfCMVl7Oefv8xgboV3OqkrahEs33KO7XwwH6hh7bnY!/b/dECE*5e9EgAA",
            "https://b256.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/tpRlB0oozaD9PyBtCmf3pQ5QY0keJJxYGX93I7n5NwQ!/b/dAyVmZiVEQAA",
            "https://b256.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/wMX2*LM6y.mBsFIYu8spAa7xXWUkPD.GHyazd.vMmYA!/b/dGYwoZjREQAA",
            "https://b255.photo.store.qq.com/psb?/V11ZojBI0Zz6pV/2vl1n0KmKTPCv944MVJgLxKAhMiM*sqajIFQ43c*9DM!/b/dPaoCJhuEQAA",
    };

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

        iv_image_url = findViewById(R.id.iv_image_url);
        // 从布局文件中获取名叫tpc_progress的文本进度圈
        tpc_progress = findViewById(R.id.tpc_progress);
        tv_image_result = findViewById(R.id.tv_image_result);
        // 从系统服务中获取下载管理器
        mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        initImageSpinner(); // 初始化下载图片的下拉框
    }

    // 初始化下载图片的下拉框
    private void initImageSpinner() {
        ArrayAdapter<String> imageUrlAdapter = new ArrayAdapter<String>(this,
                R.layout.item_select, imageDescArray);
        sp_image_url = findViewById(R.id.sp_image_url);
        sp_image_url.setPrompt("请选择要下载的图片");
        sp_image_url.setAdapter(imageUrlAdapter);
        sp_image_url.setOnItemSelectedListener(new ImageUrlSelectedListener());
        sp_image_url.setSelection(0);
    }

    class ImageUrlSelectedListener implements OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            if (isFirstSelect) { // 刚打开页面时不需要执行下载动作
                isFirstSelect = false;
                return;
            }
            startDownload(arg2); // 开始下载指定序号的图片文件
        }

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

    // 开始下载指定序号的图片文件
    private void startDownload(int pos) {
        iv_image_url.setImageDrawable(null); // 清空图像视图
        tpc_progress.setProgress(0); // 设置文本进度圈的当前进度为0,最大进度为100
        tpc_progress.setVisibility(View.VISIBLE); // 显示文本进度圈
        Uri uri = Uri.parse(imageUrlArray[pos]); // 根据图片的下载地址构建一个路径对象
        Request down = new Request(uri); // 创建一个下载请求对象,指定从哪里下载文件
        // 设置允许下载的网络类型
        down.setAllowedNetworkTypes(Request.NETWORK_MOBILE | Request.NETWORK_WIFI);
        down.setNotificationVisibility(Request.VISIBILITY_HIDDEN); // 设置不在通知栏显示
        // 设置下载文件在本地的保存路径
        down.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DCIM, pos + ".jpg");
        mDownloadId = mDownloadManager.enqueue(down); // 把下载请求对象加入到下载队列
        mHandler.post(mRefresh); // 启动下载进度的刷新任务
    }

    private Handler mHandler = new Handler(Looper.myLooper()); // 声明一个处理器对象
    // 定义一个下载进度的刷新任务
    private Runnable mRefresh = new Runnable() {
        @Override
        public void run() {
            boolean isFinish = false;
            DownloadManager.Query down_query = new DownloadManager.Query(); // 创建一个下载查询对象,按照下载编号过滤
            down_query.setFilterById(mDownloadId); // 设置下载查询对象的编号过滤器
            // 向下载管理器查询下载任务,并返回查询结果集的游标
            Cursor cursor = mDownloadManager.query(down_query);
            while (cursor.moveToNext()) {
                int uriIdx = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
                int mediaIdx = cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE);
                int totalIdx = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
                int nowIdx = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
                int statusIdx = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
                if (cursor.getString(uriIdx) == null) {
                    break;
                }
                // 根据总大小和已下载大小,计算当前的下载进度
                int progress = (int) (100 * cursor.getLong(nowIdx) / cursor.getLong(totalIdx));
                tpc_progress.setProgress(progress); // 设置文本进度圈的当前进度
                if (progress == 100) { // 下载完毕
                    isFinish = true;
                }
                // 获得实际的下载状态
                int status = isFinish ? DownloadManager.STATUS_SUCCESSFUL : cursor.getInt(statusIdx);
                mImageUri = Uri.parse(cursor.getString(uriIdx));
                String desc = String.format("文件路径:%s\n媒体类型:%s\n文件总大小:%d字节" +
                                "\n已下载大小:%d字节\n下载进度:%d%%\n下载状态:%s",
                        mImageUri.toString(), cursor.getString(mediaIdx), cursor.getLong(totalIdx),
                        cursor.getLong(nowIdx), progress, mStatusMap.get(status));
                tv_image_result.setText(desc); // 显示图片下载任务的下载详情
            }
            cursor.close(); // 关闭数据库游标
            if (!isFinish) { // 下载未完成,则继续刷新
                mHandler.postDelayed(this, 50); // 延迟50毫秒后再次启动刷新任务
            } else { // 下载已完成,则显示图片
                tpc_progress.setVisibility(View.INVISIBLE); // 隐藏文本进度圈
                iv_image_url.setImageURI(mImageUri); // 设置图像视图的图片路径
            }
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacks(mRefresh); // 移除刷新任务
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2022-10-18 21:16  小白龙白龙马  阅读(335)  评论(0编辑  收藏  举报