zoukankan      html  css  js  c++  java
  • 一手遮天 Android

    项目地址 https://github.com/webabcd/AndroidDemo
    作者 webabcd

    一手遮天 Android - 后台服务: DownloadManager

    示例如下:

    /service/DownloadManagerDemo1.java

    /**
     * DownloadManager 的示例(下载任务会在通知栏显示,即使 app 被杀也能继续下载)
     * 本例以一个 apk 文件下载为例,演示如何新增任务,删除任务,获取任务状态和下载进度,以及下载完成后弹出安装界面
     *
     * 注:
     * 1、我这里模拟器运行失败,真机运行正常
     * 2、请先进入 /storage/StorageDemo3.java 动态申请权限(我懒得在这里写了)
     */
    
    package com.webabcd.androiddemo.service;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.app.DownloadManager;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Bundle;
    import android.os.Environment;
    import android.os.StrictMode;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    import com.webabcd.androiddemo.R;
    
    import java.io.File;
    import java.util.Locale;
    
    public class DownloadManagerDemo1 extends AppCompatActivity {
    
        private final String LOG_TAG = "DownloadManagerDemo1";
    
        private Thread mThread;
        private DownloadManager mDownloadManager;
        private long mDownloadId = -1; // 下载任务的唯一标识
    
        private boolean mRegistered = false;
        private DownloadReceiver mDownloadReceiver;
    
        private Button mButton1;
        private Button mButton2;
        private Button mButton3;
        private TextView mTextView1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_service_downloadmanagerdemo1);
    
            mButton1 = findViewById(R.id.button1);
            mButton2 = findViewById(R.id.button2);
            mButton3 = findViewById(R.id.button3);
            mTextView1 = findViewById(R.id.textView1);
    
            sample();
            registerReceiver();
        }
    
        private void sample() {
            // 新增下载任务
            mButton1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // 用于在 7.0 或以上系统,让下载的 apk 文件可以被直接安装(否则会因为读取不到 apk 而无法安装)
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        StrictMode.VmPolicy.Builder localBuilder = new StrictMode.VmPolicy.Builder();
                        StrictMode.setVmPolicy(localBuilder.build());
                    }
    
                    // 通过下载地址实例化 DownloadManager.Request 对象
                    String downloadUrl = "https://mmgrapp-75037.gzc.vod.tencent-cloud.com/secure/GodDresser/1/2/3/102027/tencentmobilemanager_20210401113919_8.11.0_android_build6724_102027.apk";
                    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
    
                    // 移动网络和 wifi 网络均可下载
                    request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
                    // 通知栏标题
                    request.setTitle("download_title");
                    // 通知栏内容
                    request.setDescription("download_description");
                    // 7.0 或以上系统适配
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        request.setRequiresDeviceIdle(false); // 是否只能在系统空闲时执行
                        request.setRequiresCharging(false); // 是否只能在充电状态下执行
                    }
    
                    // 下载过程和下载完成后通知栏有通知消息
                    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE | DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                    // 隐藏通知栏的下载任务的消息,需要在 AndroidManifest.xml 配置权限 <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
                    // request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
                    // 下载文件的类型为 apk
                    request.setMimeType("application/vnd.android.package-archive");
                    // 指定文件保存地址,需要动态申请权限,否则会报错 No permission to write to...(懒得写了,请先进入 /storage/StorageDemo3.java 动态申请权限)
                    File file = new File(Environment.getExternalStorageDirectory(), "myTest.apk");
                    Log.d(LOG_TAG, "localUrl: " + Uri.fromFile(file).toString());
                    request.setDestinationUri(Uri.fromFile(file));
    
                    // 实例化 DownloadManager
                    mDownloadManager = (DownloadManager)DownloadManagerDemo1.this.getSystemService(Context.DOWNLOAD_SERVICE);
                    // 将下载请求加入下载队列,返回数据为该下载任务的标识
                    mDownloadId = mDownloadManager.enqueue(request);
                    Log.d(LOG_TAG, "downloadId: " + mDownloadId);
                }
            });
    
            // 删除当前的下载任务(如何手动 pause/resume 呢?我不知道)
            mButton2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (mDownloadId > -1) {
                        mDownloadManager = (DownloadManager) DownloadManagerDemo1.this.getSystemService(Context.DOWNLOAD_SERVICE);
                        mDownloadManager.remove(mDownloadId);
                    }
                }
            });
    
            // 跳转到系统下载界面
            mButton3.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    DownloadManagerDemo1.this.startActivity(new android.content.Intent(DownloadManager.ACTION_VIEW_DOWNLOADS));
                }
            });
    
            // 获取任务状态
            mThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        while (true) {
                            if (mDownloadId == -1) {
                                continue;
                            }
    
                            // 实例化 DownloadManager.Query 对象
                            DownloadManager.Query query = new DownloadManager.Query();
                            // 查询指定的 downloadId(可以不指定查询条件,那样就是查询全部下载任务)
                            query.setFilterById(mDownloadId);
                            // 根据查询条件获取游标
                            Cursor cursor = mDownloadManager.query(query);
                            if (cursor.moveToFirst()) {
    
                                int downloadIdIndex = cursor.getColumnIndex(DownloadManager.COLUMN_ID);
                                int remoteUrlIndex = cursor.getColumnIndex(DownloadManager.COLUMN_URI);
                                int localUrlIndex = 0;
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                                    // 7.0 或以上系统使用 COLUMN_LOCAL_URI 字段
                                    localUrlIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
                                } else {
                                    localUrlIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
                                }
                                int totalBytesIndex = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
                                int downloadedBytesIndex = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
                                int taskStatusIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
    
                                // 以下几个字段看名字就知道意思,就不细说了
                                long downloadId = cursor.getLong(downloadIdIndex);
                                String remoteUrl = cursor.getString(remoteUrlIndex);
                                String localUrl = cursor.getString(localUrlIndex);
                                long totalBytes = cursor.getLong(totalBytesIndex);
                                long downloadedBytes = cursor.getLong(downloadedBytesIndex);
    
                                // 任务状态包括如下几个可能的值
                                // DownloadManager.STATUS_PENDING, DownloadManager.STATUS_RUNNING, DownloadManager.STATUS_PAUSED, DownloadManager.STATUS_SUCCESSFUL, DownloadManager.STATUS_FAILED
                                int taskStatus = cursor.getInt(taskStatusIndex);
    
                                writeMessage(String.format(Locale.US, "downloadId:%d
    remoteUrl:%s
    localUrl:%s
    totalBytes:%d
    downloadedBytes:%d
    taskStatus:%d",
                                        downloadId, remoteUrl, localUrl, totalBytes, downloadedBytes, taskStatus));
                            }
                            cursor.close();
    
                            if (Thread.interrupted()) {
                                break;
                            }
                            Thread.sleep(1000);
                        }
                    } catch (InterruptedException e) {
                        Log.d(LOG_TAG, "线程被 interrupted 了");
                    }
                }
            });
            mThread.setName("thread_DownloadManagerDemo1");
            mThread.setDaemon(true);
            mThread.start();
        }
    
        private void writeMessage(final String message) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mTextView1.setText(message);
                }
            });
        }
    
        @Override
        public void onDestroy() {
            if (mThread != null) {
                mThread.interrupt();
                mThread = null;
            }
    
            unregisterReceiver();
    
            super.onDestroy();
        }
    
    
    
        // 通过监听广播,获取任务完成事件(也可以通过轮询任务的方式获取下载任务是否完成)和通知栏中的任务点击事件(这个只能通过广播来获取了)
        public void registerReceiver() {
            mDownloadReceiver = new DownloadReceiver();
            IntentFilter filter = new IntentFilter();
            filter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE); // 下载任务完成的广播
            filter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED); // 在通知栏点击下载任务之后的广播
            this.registerReceiver(mDownloadReceiver, filter);
            mRegistered = true;
        }
        public void unregisterReceiver() {
            if (mRegistered) {
                try {
                    this.unregisterReceiver(mDownloadReceiver);
                    mRegistered = false;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        public class DownloadReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                // 下载任务完成
                if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                    // 获取当前完成的下载任务的 downloadId
                    long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
    
                    // 通过 downloadId 获取本地文件地址
                    DownloadManager downloadManager = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
                    Uri localUri = downloadManager.getUriForDownloadedFile(downloadId);
                    if (localUri != null) {
                        // 弹出 apk 安装界面
                        Intent install = new Intent(Intent.ACTION_VIEW);
                        install.setDataAndType(localUri, "application/vnd.android.package-archive");
                        install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        context.startActivity(install);
                    } else {
                        Log.e(LOG_TAG, "download error");
                    }
                }
                // 在通知栏点击下载任务之后,则跳转到系统下载界面
                else if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
                    Intent viewDownloadIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
                    viewDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(viewDownloadIntent);
                }
            }
        }
    }
    

    /layout/activity_service_downloadmanagerdemo1.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/button1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="新增下载任务" />
    
        <Button
            android:id="@+id/button2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="删除当前的下载任务" />
    
        <Button
            android:id="@+id/button3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="跳转到系统下载界面" />
    
        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    

    项目地址 https://github.com/webabcd/AndroidDemo
    作者 webabcd

  • 相关阅读:
    马踏棋盘的贪心算法
    Windows Phone开发(13):如何规范用户的输入行为
    Windows Phone开发(16):样式和控件模板
    Windows Phone开发(18):变形金刚第九季——变换
    Windows Phone开发(10):常用控件(上)
    Windows Phone开发(14):数据模板
    Windows Phone开发(12):认识一下独具个性的磁贴
    Windows Phone开发(15):资源
    Windows Phone开发(11):常用控件(下)
    Windows Phone开发(17):URI映射
  • 原文地址:https://www.cnblogs.com/webabcd/p/android_service_DownloadManagerDemo1.html
Copyright © 2011-2022 走看看