【Android】WorkManager(章二)

剩余的三部分
官方文档

案例

实现下载器,并监听下载进度

界面

定义Worker

在官方案例的前提下,进行完善

下载download



下载进度

授予权限


开始工作并监听

完整代码

MainActivity.java

java 复制代码
package com.test.downloadworkerapplication;

import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC;
import static com.test.downloadworkerapplication.MainActivity.MY_LOG_TAG;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.work.Data;
import androidx.work.ForegroundInfo;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class DownloadWorker extends Worker {
    public static final String KEY_INPUT_URL = "KEY_INPUT_URL";
    public static final String KEY_OUTPUT_FILE_NAME = "KEY_OUTPUT_FILE_NAME";
    public static final String KEY_FILE_URI = "KEY_FILE_URI";
    public static final String PROGRESS = "PROGRESS";

    private final NotificationManager notificationManager;

    public DownloadWorker(
            @NonNull Context context,
            @NonNull WorkerParameters parameters) {
        super(context, parameters);
        notificationManager = (NotificationManager)
                context.getSystemService(NOTIFICATION_SERVICE);

        Data data = new Data.Builder().putInt(PROGRESS, 0).build();
        setProgressAsync(data);
    }

    @NonNull
    @Override
    public Result doWork() {
        Data inputData = getInputData();
        String inputUrl = inputData.getString(KEY_INPUT_URL);
        String outputFile = inputData.getString(KEY_OUTPUT_FILE_NAME);

        String progress = "Starting Download";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            setForegroundAsync(createForegroundInfo(progress));
        }
        Uri uri = download(inputUrl, outputFile);

        Data progressData2 = new Data.Builder().putInt(PROGRESS, 100).build();
        setProgressAsync(progressData2);

        Data data = new Data.Builder()
                .putString(KEY_FILE_URI, uri.toString())
                .build();
        return Result.success(data);
    }

    private Uri download(String inputUrl, String outputFile) {
        // Downloads a file and updates bytes read
        // Calls setForegroundAsync(createForegroundInfo(myProgress))
        // periodically when it needs to update the ongoing Notification.
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                String myProgress = "downloading...";
                setForegroundAsync(createForegroundInfo(myProgress));
            }

            long fileSize = FileSizeFetcher.getFileSize(inputUrl);
            URL url = new URL(inputUrl);
            InputStream inputStream = url.openStream();

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            int downloadLen = 0;
            while ((len = inputStream.read(buffer)) != -1) {
                downloadLen += len;
                byteArrayOutputStream.write(buffer, 0, len);

                /// 下载进度
                double progress = 1.0 * downloadLen / fileSize;
                Data data = new Data.Builder().putDouble(PROGRESS, progress).build();
                setProgressAsync(data);
            }
            byte[] byteArray = byteArrayOutputStream.toByteArray();
            inputStream.close();

            File file = new File(getApplicationContext().getCacheDir(), outputFile + ".pdf");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(byteArray);
            fileOutputStream.close();

            String absolutePath = file.getAbsolutePath();
            Log.i(MY_LOG_TAG, absolutePath);
            return Uri.fromFile(file);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @NonNull
    private ForegroundInfo createForegroundInfo(@NonNull String progress) {
        // Build a notification using bytesRead and contentLength
        Context context = getApplicationContext();
        String id = context.getString(R.string.notification_channel_id);
        String title = context.getString(R.string.notification_title);
        String cancel = context.getString(R.string.cancel_download);
        // This PendingIntent can be used to cancel the worker
        PendingIntent intent = WorkManager.getInstance(context)
                .createCancelPendingIntent(getId());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createChannel(id);
        }

        Notification notification = new NotificationCompat.Builder(context, id)
                .setContentTitle(title)
                .setTicker(title)
                .setContentText(progress)
                .setSmallIcon(R.drawable.ic_work_notification)
                .setOngoing(true)
                // Add the cancel action to the notification which can
                // be used to cancel the worker
                .addAction(android.R.drawable.ic_delete, cancel, intent)
                .build();

        int notificationId = 1000;
        return new ForegroundInfo(notificationId, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC);
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private void createChannel(String id) {
        // Create a Notification channel
        NotificationChannel channel = new NotificationChannel(id, "download channel", NotificationManager.IMPORTANCE_NONE);
        notificationManager.createNotificationChannel(channel);
    }
}

DownloadWorker.java

java 复制代码
package com.test.downloadworkerapplication;

import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC;
import static com.test.downloadworkerapplication.MainActivity.MY_LOG_TAG;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.work.Data;
import androidx.work.ForegroundInfo;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class DownloadWorker extends Worker {
    public static final String KEY_INPUT_URL = "KEY_INPUT_URL";
    public static final String KEY_OUTPUT_FILE_NAME = "KEY_OUTPUT_FILE_NAME";
    public static final String KEY_FILE_URI = "KEY_FILE_URI";
    public static final String PROGRESS = "PROGRESS";

    private final NotificationManager notificationManager;

    public DownloadWorker(
            @NonNull Context context,
            @NonNull WorkerParameters parameters) {
        super(context, parameters);
        notificationManager = (NotificationManager)
                context.getSystemService(NOTIFICATION_SERVICE);

        Data data = new Data.Builder().putInt(PROGRESS, 0).build();
        setProgressAsync(data);
    }

    @NonNull
    @Override
    public Result doWork() {
        Data inputData = getInputData();
        String inputUrl = inputData.getString(KEY_INPUT_URL);
        String outputFile = inputData.getString(KEY_OUTPUT_FILE_NAME);

        String progress = "Starting Download";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            setForegroundAsync(createForegroundInfo(progress));
        }
        Uri uri = download(inputUrl, outputFile);

        Data progressData2 = new Data.Builder().putInt(PROGRESS, 100).build();
        setProgressAsync(progressData2);

        Data data = new Data.Builder()
                .putString(KEY_FILE_URI, uri.toString())
                .build();
        return Result.success(data);
    }

    private Uri download(String inputUrl, String outputFile) {
        // Downloads a file and updates bytes read
        // Calls setForegroundAsync(createForegroundInfo(myProgress))
        // periodically when it needs to update the ongoing Notification.
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                String myProgress = "downloading...";
                setForegroundAsync(createForegroundInfo(myProgress));
            }

            long fileSize = FileSizeFetcher.getFileSize(inputUrl);
            URL url = new URL(inputUrl);
            InputStream inputStream = url.openStream();

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            int downloadLen = 0;
            while ((len = inputStream.read(buffer)) != -1) {
                downloadLen += len;
                byteArrayOutputStream.write(buffer, 0, len);

                /// 下载进度
                double progress = 1.0 * downloadLen / fileSize;
                Data data = new Data.Builder().putDouble(PROGRESS, progress).build();
                setProgressAsync(data);
            }
            byte[] byteArray = byteArrayOutputStream.toByteArray();
            inputStream.close();

            File file = new File(getApplicationContext().getCacheDir(), outputFile + ".pdf");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(byteArray);
            fileOutputStream.close();

            String absolutePath = file.getAbsolutePath();
            Log.i(MY_LOG_TAG, absolutePath);
            return Uri.fromFile(file);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @NonNull
    private ForegroundInfo createForegroundInfo(@NonNull String progress) {
        // Build a notification using bytesRead and contentLength
        Context context = getApplicationContext();
        String id = context.getString(R.string.notification_channel_id);
        String title = context.getString(R.string.notification_title);
        String cancel = context.getString(R.string.cancel_download);
        // This PendingIntent can be used to cancel the worker
        PendingIntent intent = WorkManager.getInstance(context)
                .createCancelPendingIntent(getId());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createChannel(id);
        }

        Notification notification = new NotificationCompat.Builder(context, id)
                .setContentTitle(title)
                .setTicker(title)
                .setContentText(progress)
                .setSmallIcon(R.drawable.ic_work_notification)
                .setOngoing(true)
                // Add the cancel action to the notification which can
                // be used to cancel the worker
                .addAction(android.R.drawable.ic_delete, cancel, intent)
                .build();

        int notificationId = 1000;
        return new ForegroundInfo(notificationId, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC);
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private void createChannel(String id) {
        // Create a Notification channel
        NotificationChannel channel = new NotificationChannel(id, "download channel", NotificationManager.IMPORTANCE_NONE);
        notificationManager.createNotificationChannel(channel);
    }
}

FileSizeFetch.java

java 复制代码
package com.test.downloadworkerapplication;

import java.net.HttpURLConnection;
import java.net.URL;

public class FileSizeFetcher {
    public static long getFileSize(String urlString) {
        long fileSize = 0;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(urlString);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("HEAD"); // 使用HEAD请求以节省带宽
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                String contentLength = connection.getHeaderField("Content-Length");
                fileSize = Long.parseLong(contentLength);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return fileSize;
    }
}

运行


相关推荐
恋猫de小郭3 小时前
腾讯 Kuikly 正式开源,了解一下这个基于 Kotlin 的全平台框架
android·前端·ios
贫道绝缘子3 小时前
【Android】四大组件之Activity
android
人生游戏牛马NPC1号3 小时前
学习Android(四)
android·kotlin
_祝你今天愉快3 小时前
安卓触摸事件分发机制分析
android
fyr897574 小时前
Ubuntu 下编译goldfish内核并使用模拟器运行
android·linux
心之所向,自强不息4 小时前
关于Android Studio的Gradle各项配置
android·ide·gradle·android studio
隐-梵4 小时前
Android studio学习之路(八)---Fragment碎片化页面的使用
android·学习·android studio
百锦再4 小时前
Kotlin学习基础知识大全(上)
android·xml·学习·微信·kotlin·studio·mobile
前期后期4 小时前
Android 智能家居开发:串口是什么,为什么android版本都比较低?粘包半包的原因以及处理思路,缓冲区处理,以及超时清空缓冲区....
android·智能家居
Wgllss4 小时前
按需下载!!全动态插件化框架WXDynamicPlugin解析怎么支持的
android·架构·android jetpack