【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;
    }
}

运行


相关推荐
张拭心5 小时前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心5 小时前
Android 17 来了!新特性介绍与适配建议
android·前端
Kapaseker7 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴7 小时前
Android17 为什么重写 MessageQueue
android
阿巴斯甜1 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android