当前位置: 首页 > news >正文

【重生之我在学Android】WorkManager (章一)

相关文章

【重生之我在学Android原生】ContentProvider(Java)
【重生之我在学Android原生】Media3
【重生之我在学Android】WorkManager (章一)

前言

官方文档
在这里插入图片描述
官方推荐 - 前台服务、后台服务都可以使用WorkManger来实现
在这里插入图片描述

案例

语言:JAVA

实现要求

一步步实现一个图片压缩APP

创建项目

在这里插入图片描述

添加WorkManager依赖

参考文章
在这里插入图片描述
添加到builder.gradle, sync一下
在这里插入图片描述

    val workVersion = "2.9.0"implementation("androidx.work:work-runtime:$workVersion")

接收share来的图片数据

在这里插入图片描述
要实现这种效果,需要在AndroidManifest.xml声明标签,过滤intent
在这里插入图片描述

<intent-filter><action android:name="android.intent.action.SEND" /><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="image/*" /></intent-filter>

将Activity改为singleTop

运行APP。打开手机相册,分享一张图片,会重新使用这个Activity
在这里插入图片描述

android:launchMode="singleTop"

在onNewIntent接收数据

在这里插入图片描述

定义Worker

你需要做什么事情,你就定义一个Worker,指派它做事,做什么事,就在dowork里定义
dowork有三个返回,见图
在这里插入图片描述

传入Uri到Worker

参考这里
在这里插入图片描述
通过inputdata传入
在这里插入图片描述
在这里插入图片描述

Uri -> Bitmap

在这里插入图片描述
若有爆红位置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

压缩图片直到图片的大小不超过XKB

传入图片的大小阀值
在这里插入图片描述
不断循环压缩,一直到图片的大小不超过20KB
在这里插入图片描述

生成文件

在这里插入图片描述
在这里插入图片描述

返回图片地址数据

构建Data,传值回去
在这里插入图片描述

监听Worker结果

在获取到WorkManager这个实例后
通过getWorkInfoByIdLiveData方法来监听workerrequest状态及结果返回
在这里插入图片描述

显示结果

在布局中,加入一张图片
在这里插入图片描述
在这里插入图片描述

Android版本 兼容问题

兼容低版本的Android系统
在这里插入图片描述
inputStream.readAllBytes() 需要在API 33之后使用
所以需要更改写法,来使低版本的Android系统使用
在这里插入图片描述

bytes = new byte[inputStream.available()];inputStream.read(bytes);

运行项目

请添加图片描述

完整代码

// ImageCompressionWorker
package com.test.imagecompressionworkerapplication;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.util.Log;import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.work.Data;
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;public class ImageCompressionWorker extends Worker {private final String TAG = "worker - log";public static final String KEY_CONTENT_URI = "KEY_CONTENT_URI";public static final String KEY_COMPRESSION_THRESHOLD = "KEY_COMPRESSION_THRESHOLD";public static final String KEY_RESULT_PATH = "KEY_RESULT_PATH";private final WorkerParameters workerParameters;private final Context appContext;public ImageCompressionWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {super(context, workerParams);appContext = context;workerParameters = workerParams;}@NonNull@Overridepublic Result doWork() {Data inputData = workerParameters.getInputData();String uriStr = inputData.getString(KEY_CONTENT_URI);long size = inputData.getLong(KEY_COMPRESSION_THRESHOLD, 0L);assert uriStr != null;Uri uri = Uri.parse(uriStr);byte[] bytes;try {InputStream inputStream = appContext.getContentResolver().openInputStream(uri);assert inputStream != null;
//            byte[] bytes_ = inputStream.readAllBytes();bytes = new byte[inputStream.available()];inputStream.read(bytes);Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);inputStream.close();int quality = 100;byte[] byteArray;do {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream);byteArray = byteArrayOutputStream.toByteArray();quality -= Math.round(quality * 0.1);} while (byteArray.length > size && quality > 5);File file = new File(appContext.getCacheDir(), workerParameters.getId() + ".jpg");FileOutputStream fileOutputStream = new FileOutputStream(file);fileOutputStream.write(byteArray);fileOutputStream.close();String absolutePath = file.getAbsolutePath();Data outputData = new Data.Builder().putString(KEY_RESULT_PATH, absolutePath).build();return Result.success(outputData);} catch (IOException e) {throw new RuntimeException(e);}}
}
// MainActivity.java
package com.test.imagecompressionworkerapplication;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;import java.util.UUID;public class MainActivity extends AppCompatActivity {private final String TAG = "mainActivity - log";private WorkManager workManager;private ImageView sharedImage;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);workManager = WorkManager.getInstance(this);bindView();}@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);Uri uri;if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {uri = intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri.class);} else {uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);}assert uri != null;long size = 1024 * 20L;Data inputData = new Data.Builder().putString(ImageCompressionWorker.KEY_CONTENT_URI, uri.toString()).putLong(ImageCompressionWorker.KEY_COMPRESSION_THRESHOLD, size).build();OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(ImageCompressionWorker.class).setInputData(inputData)
//                .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST).build();workManager.enqueue(oneTimeWorkRequest);UUID id = oneTimeWorkRequest.getId();workManager.getWorkInfoByIdLiveData(id).observe(this, workInfo -> {if (workInfo.getState() == WorkInfo.State.SUCCEEDED) {Data outputData = workInfo.getOutputData();String filePath = outputData.getString(ImageCompressionWorker.KEY_RESULT_PATH);Bitmap bitmap = BitmapFactory.decodeFile(filePath);sharedImage.setImageBitmap(bitmap);}});}private void bindView() {sharedImage = findViewById(R.id.sharedImage);}
}

更多内容

这一节,有些流水账,看看就好
可以直接看官方文档吧
官方文档

执行加急工作

在这里插入图片描述
在这里插入图片描述

配额策略

在这里插入图片描述

加急工作 + CoroutineWorker + 通知

加急工作需要配合通知使用,否则会报错
将之前的继承Worker改为CoroutineWorker
重写方法getForegroundInfo
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

    @Nullable@Overridepublic Object getForegroundInfo(@NonNull Continuation<? super ForegroundInfo> $completion) {return new ForegroundInfo(NOTIFICATION_ID, createNotification());}private Notification createNotification() {String CHANNEL_ID = "compressor_channel_id";String CHANNEL_NAME = "压缩图片通知通道";String NOTIFICATION_TITLE = "你有一个程序在压缩图片";int importance = NotificationManager.IMPORTANCE_HIGH;NotificationChannel notificationChannel;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {notificationChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance);NotificationManager notificationManager = getSystemService(appContext, NotificationManager.class);assert notificationManager != null;notificationManager.createNotificationChannel(notificationChannel);}String NOTIFICATION_TEXT = "压缩中...";Intent intent = new Intent(appContext, ImageCompressionWorker.class);PendingIntent pendingIntent = PendingIntent.getActivity(appContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);return new NotificationCompat.Builder(appContext, CHANNEL_ID).setContentTitle(NOTIFICATION_TITLE).setContentText(NOTIFICATION_TEXT).setSmallIcon(R.drawable.ic_launcher_background).setContentIntent(pendingIntent).build();}

通知

在这里插入图片描述
在Android 12 之前的版本运行,会有通知显示;
通知需要申请权限

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

在这里插入图片描述

private static final String[] PERMISSION_REQUIRED = new String[]{Manifest.permission.POST_NOTIFICATIONS};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);workManager = WorkManager.getInstance(this);bindView();if (!checkAllPermissions()) {requestPermissions(PERMISSION_REQUIRED, REQUEST_CODE);}}private boolean checkAllPermissions() {for (String permission : PERMISSION_REQUIRED) {int permissionCheck = ContextCompat.checkSelfPermission(this, permission);if (permissionCheck == PackageManager.PERMISSION_DENIED) {return false;}}return true;}

运行项目

压缩过程很快,压缩完成之后,通知关闭了
请添加图片描述

调度定期工作

每间隔一小时的最后15分钟工作一次
在这里插入图片描述
为了方便测试,这里使用15分钟一次

WorkRequest uploadRequest = new PeriodicWorkRequest.Builder(PeriodicUploadLogWorker.class, 15, TimeUnit.MINUTES, 15, TimeUnit.MINUTES).build();WorkManager workManager = WorkManager.getInstance(this);workManager.enqueue(uploadRequest);
public class PeriodicUploadLogWorker extends Worker {private final String TAG = "periodic_upload_log";public PeriodicUploadLogWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {super(context, workerParams);}@NonNull@Overridepublic Result doWork() {uploadLog();return Result.success();}private void uploadLog() {Log.i(TAG, String.valueOf(System.currentTimeMillis()));}
}

在这里插入图片描述

工作约束

将工作延迟到满足最佳条件时运行
在这里插入图片描述
在这里插入图片描述

延迟工作

在这里插入图片描述

重试和退避政策

在这里插入图片描述
在这里插入图片描述

标记工作

在这里插入图片描述
在这里插入图片描述

分配输入数据

setInputData 传入数据
getInputData 获取数据
在这里插入图片描述
在这里插入图片描述

唯一工作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

查询工作

按id、name、tag查询
在这里插入图片描述
WorkQuery
在这里插入图片描述

取消工作

在这里插入图片描述

链接工作

将每个Worker链接起来,按顺序执行。
在这里插入图片描述

还可以定义合并器
在这里插入图片描述
默认合并器,变量名一致的,值采用最新的覆盖前者
在这里插入图片描述
在这里插入图片描述
第二种,会保留返回的结果,会合并相同变量名到一个数组中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

长时间运行worker

观察Worker的中间进度

更新工作

相关文章:

【重生之我在学Android】WorkManager (章一)

相关文章 【重生之我在学Android原生】ContentProvider(Java) 【重生之我在学Android原生】Media3 【重生之我在学Android】WorkManager &#xff08;章一&#xff09; 前言 官方文档 官方推荐 - 前台服务、后台服务都可以使用WorkManger来实现 案例 语言&#xff1a;JA…...

【强训笔记】day23

NO.1 思路&#xff1a;直接计算结果&#xff0c;先计算怪物可以抗几次攻击&#xff0c;再计算勇士受到的伤害&#xff0c;如果勇士的攻击力大于等于怪物的血量&#xff0c;那么就可以击杀无数只&#xff0c;如果勇士的血量正好是受到攻击的整数倍&#xff0c;那么击杀的怪物数…...

C语言-STM32:介绍PWM,并使用PWM实现呼吸灯

1、什么是PWM PWM&#xff0c;全称为Pulse Width Modulation&#xff0c;中文名为脉冲宽度调制。这是一种模拟控制技术&#xff0c;通过改变脉冲信号的宽度来表征一个连续变量的平均值&#xff0c;通常用于对模拟信号的数字化控制&#xff0c;特别是在功率转换和信号处理中非常…...

SpringBean详解

文章目录 概述Spring获取Bean的流程依赖注入bean的作用域Spring 中的 Bean 是线程安全的吗Spring如何处理线程并发问题bean 的自动装配和方式Resource和Autowired的区别bean的自动装配bean的生命周期BeanFactoryBeanFactory 常用的实现类有哪些BeanFactory与FactoryBean的不同A…...

hive获取这周五到下周四的区间,周一到周日的区间

-- 获取每个日期所在周期的开始和结束时间 SELECTcreated_date AS date_in_period,CASEWHEN date_format(created_date, u) < 5 THEN date_sub(created_date, cast(date_format(created_date, u) AS INT) 2)ELSE date_sub(created_date, cast(date_format(created_date, u)…...

Iterable与Iterator

Iterator public interface Iterator<E> {} terator是一个接口&#xff0c;它是集合的迭代器。集合可以通过Iterator去遍历集合中的元素。Iterator提供的API接口如下&#xff1a; forEachRemaining(Consumer<? super E> action)&#xff1a;为每个剩余元素执行给…...

免费Premiere模板,几何图形元素动画视频幻灯片模板素材下载

Premiere Pro模板&#xff0c;几何图形元素动画视频幻灯片模板 &#xff0c;组织良好&#xff0c;易于自定义。包括PDF教程。 项目特点&#xff1a; 使用Adobe Premiere Pro 2021及以上版本。 19201080全高清。 不需要插件。 包括帮助视频。 免费下载&#xff1a;https://prmu…...

数据结构与算法学习笔记九---循环队列的表示和实现(C++)

目录 前言 1.为什么要使用循环队列 2.队列的顺序存储方式的实现 1.定义 2.队列初始化 3.销毁 4.清空队列 5.队列是否为空 6.队列长度 7.队头 8.入队 9.出队 10.遍历队列 11.完整代码 3.参考资料 前言 这篇文章介绍循环队列的表示和用法。 1.为什么要使用循环队…...

Mysql获取当前时间

1、今天开始时间和结束时间 SELECT DATE_FORMAT(NOW(),’%Y-%m-%d 00:00:00’) AS ‘今天开始’; SELECT DATE_FORMAT(NOW(),’%Y-%m-%d 23:59:59’) AS ‘今天结束’;2、昨天的开始时间和结束时间 SELECT DATE_FORMAT( DATE_SUB(CURDATE(), INTERVAL 1 DAY), ‘%Y-%m-%d 00:…...

计算机服务器中了locked勒索病毒怎么解决,locked勒索病毒解密恢复工具

在网络技术飞速发展的时代&#xff0c;通过网络开展各项工作业务成为众多企业的首选&#xff0c;网络也为企业的生产运营提供了极大便利&#xff0c;大大提升了企业办公效率&#xff0c;但是利用网络避免不了网络威胁的存在&#xff0c;数据安全问题一直是企业关心的主要话题。…...

基于springboot实现的在线动漫信息平台

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven…...

C# Winform+Halcon结合标准视觉工具

介绍 winform与halcon结合标准化工具实例 软件架构 软件架构说明 基于NET6 WINFORMHALCON 实现标准化视觉检测工具 集成相机通讯 集成PLC通讯 TCP等常见通讯 支持常见halcon算子 图形采集blob分析高精度匹配颜色提取找几何体二维码提取OCR识别等等 。。。 安装教程 …...

英语单词量测试

网址&#xff1a;https://preply.com/en/learn/english/test-your-vocab 测试结果&#xff1a; 细节&#xff1a;英语母语者有20000-35000个单词的词汇量&#xff0c;8岁孩子的词汇量在8000个左右。而不是我们教育系统里说的&#xff0c;6000个单词足够用了。足够用&#xff0…...

三、安装node_exporter

目录 一、简介 二、下载安装 一、简介 Exporter是Prometheus的指标数据收集组件。它负责从目标Jobs收集数据&#xff0c;并把收集到的数据转换为Prometheus支持的时序数据格式。 和传统的指标数据收集组件不同的是&#xff0c;他只负责收集&#xff0c;并不向Server端发送数据…...

kafka基础知识

kafka架构 producer -> kafka cluster(broker>topic>partition) -> consumer -> zookeeper kafka压测 kafka-producer-perf-test.sh kafka-consumer-perf-test.sh kafka日志保存位置及消息保存时间 /tpdata/client/Kafka/kafka/config/server.properties log.…...

华为昇腾310B1平台视频解码失败[ERROR] Send frame to vdec failed, errorno:507018

目录 1 [ERROR] Send frame to vdec failed, errorno:507018 2 bug解决尝试1 3 bug解决尝试2 4 最终解决方法 参考文献&#xff1a; 1 [ERROR] Send frame to vdec failed, errorno:507018 某项目中的代码运行报错 [ERROR] Send frame to vdec failed, errorno:507018 Ac…...

Flutter 中的 SwitchListTile 小部件:全面指南

Flutter 中的 SwitchListTile 小部件&#xff1a;全面指南 在Flutter的Material组件库中&#xff0c;SwitchListTile是一个包含开关&#xff08;Switch&#xff09;的列表项&#xff0c;非常适合用来创建带有标题、副标题以及开关的列表项&#xff0c;常用于设置界面&#xff…...

详细分析Vue3中的defineExpose(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 其基本知识可参考官网&#xff1a;Vue3中的defineExpose 1. 基本知识 defineExpose 是 Vue 3 的 Composition API 中一个新的实用函数&#xff0c;用于在 <script setup> 语法下显式暴露组件的公共属性和方法 这在处理子组件…...

合合信息:TextIn文档解析技术与高精度文本向量化模型再加速

文章目录 前言现有大模型文档解析问题表格无法解析无法按照阅读顺序解析文档编码错误 诉求文档解析技术技术难点技术架构关键技术回根溯源 文本向量化模型结语 前言 随着人工智能技术的持续演进&#xff0c;大语言模型在我们日常生活中正逐渐占据举足轻重的地位。大模型语言通…...

Git与Gitlab

第1章Git概述 Git是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的各种项目。 代码托管中心&#xff0c;记录每个版本的代码&#xff0c;从项目创建到现在使用的代码&#xff0c;中间所有的修改都有记录。 1. 何为版本控制 版本控制是…...

快速解密QQ音乐加密文件:qmc-decoder完整指南

快速解密QQ音乐加密文件&#xff1a;qmc-decoder完整指南 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder 还在为QQ音乐下载的.qmc、.qmc3、.qmcflac格式文件无法在其他播放…...

AArch64虚拟内存系统架构与64KB粒度地址转换详解

1. AArch64虚拟内存系统架构概述现代处理器架构通过虚拟内存机制实现物理内存与虚拟地址空间的隔离映射&#xff0c;AArch64作为ARMv8/ARMv9架构的64位执行状态&#xff0c;其虚拟内存系统架构&#xff08;VMSA&#xff09;采用多级页表机制实现地址转换。与传统x86架构相比&am…...

一线观察:赣州新房装修公司的可靠细节

上个月&#xff0c;有个老朋友找我帮他参谋新房装修的事。赣州章江新区某刚交付的高端盘&#xff0c;精装改毛坯&#xff0c;180平的大户型。他跟我说&#xff0c;前后跑了五六家装修公司&#xff0c;聊完最大的感觉是——云里雾里。报价单看不懂方案&#xff0c;总觉得藏着坑&…...

给工程师的傅里叶变换:从信号处理到图像压缩,用Python代码理解核心推导

给工程师的傅里叶变换&#xff1a;从信号处理到图像压缩&#xff0c;用Python代码理解核心推导 当你在Spotify上听歌时&#xff0c;算法如何从嘈杂环境中分离人声&#xff1f;手机拍照时&#xff0c;JPEG压缩为何能大幅减小文件体积却保持清晰&#xff1f;这些看似不相关的技术…...

FreeRTOS移植避坑指南:当你的芯片不在官方支持列表时(以S3C2440为例)

FreeRTOS移植实战&#xff1a;非官方支持芯片的定制化开发方法论 当你的项目需要将FreeRTOS移植到非官方支持芯片时&#xff0c;整个过程就像在未知海域航行——没有现成的海图&#xff0c;但掌握正确的导航方法同样能到达目的地。以经典的ARM9芯片S3C2440为例&#xff0c;这种…...

AI服务先看工作流

很多人买 AI 服务时&#xff0c;还是按买会员的方式看&#xff1a;哪个模型名气大&#xff0c;哪个月费便宜&#xff0c;哪个 Token 多。这个习惯很自然&#xff0c;但它很容易把钱花在用不起来的地方。 最近几个问题放在手边看&#xff0c;会发现同一个提醒。手机店卖不动新机…...

大模型注意力机制深度解析:从Dot-Product到Flash Attention的演进之路

引言如果让你用一句话概括过去七年人工智能领域最重要的技术突破&#xff0c;答案几乎毫无悬念——注意力机制&#xff08;Attention Mechanism&#xff09; 。2017年&#xff0c;Google团队在论文《Attention Is All You Need》中首次提出Transformer架构&#xff0c;彻底摒弃…...

FanControl完全指南:5步打造Windows风扇智能控制系统

FanControl完全指南&#xff1a;5步打造Windows风扇智能控制系统 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/…...

【实战】Latex|在保留ACM-Reference-Format格式的前提下,实现参考文献按引用顺序排列

1. 问题背景与核心痛点 当你使用ACM官方模板撰写论文时&#xff0c;参考文献格式要求必须采用ACM-Reference-Format样式。这个格式有个让人头疼的特性&#xff1a;它会强制按作者姓氏字母顺序排列参考文献&#xff0c;而不是按照文中实际引用顺序。想象一下&#xff0c;你精心设…...

RT-Thread USB HID设备数据发送失败排查:ops参数与报告ID的深度解析

1. 问题背景与核心需求解析 最近在捣鼓RT-Thread&#xff0c;想用它来实现一个USB HID设备&#xff0c;完成和电脑之间的双向数据收发。HID&#xff0c;也就是人机接口设备&#xff0c;大家最熟悉的可能就是键盘鼠标了&#xff0c;它的好处是免驱动&#xff0c;在主流操作系统…...