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

安卓开发后台应用周期循环获取位置信息上报服务器

问题背景

最近有需求,在APP启动后,退到后台,还要能实现周期获取位置信息上报服务器,研究了一下实现方案。

问题分析

一、APP退到后台后网络请求实现
APP退到后台后,实现周期循环发送网络请求。目前尝试了两种方案是OK,如下:
(1)AlarmManager + 前台服务 +广播的方案,可以正常实现,大体思路是,启动一个前台服务,使用AlarmManager发起一个定时广播,然后广播接收器接收到广播后,循环去执行service的操作。
(2)使用jetpeck库提供的worker实现,基于PeriodicWorkRequest实现一个周期执行的任务,比如周期设置为15分钟,可以在后台稳定执行。
二、APP退到后台后获取地理位置实现
APP申请位置时,用户选择了列表中的始终允许后,APP在后台是可以正常获取到位置信息的。不过这里有个坑,因为安卓11版本后退位置信息管控策略进行了更新,如果APP的target sdk版本大于29时,需要分别申请前台位置权限和后台位置权限,本APPtargetsdk是小于等于29的,可以同时申请前台位置权限和后台位置权限。(compileSdkVersion小于29时,会没有这个后台位置权限,需要最好升级到29)

问题解决

下面展示大概的代码,可以参考实现。
(1)引入依赖

api('androidx.work:work-runtime:2.0.1')

(2)manifest文件中增加申请权限

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 这个权限用于访问GPS定位 --><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 --><uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

(3)权限申请(同时申请位置权限和后台位置权限)

        RxPermissionHelper helper = new RxPermissionHelper(this);helper.requestEach(new RxPermissionHelper.PermissionCallback() {@Overridepublic void granted(String permissionName) {LogUtil.writerLog("ACCESS_FINE_LOCATION granted");}@Overridepublic void denied(String permissionName, boolean forever) {}@Overridepublic void result(boolean allGranted) {}}, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION);

(4)work类:去执行前台服务


/*** work类执行定时任务*/
public class SimpleWorker extends Worker {private CurPosUtil curPosUtil;public SimpleWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {super(context, workerParams);}@NonNull@Overridepublic Result doWork() {Log.d("baorant", "执行调度任务");LogUtil.writerLog("执行调度任务");startService();return Result.success();}private void startService() {
//        curPosUtil = new CurPosUtil(getApplicationContext());Intent intent = new Intent(getApplicationContext(), RecordService.class);getApplicationContext().startService(intent);}
}

(5)RecordService前台服务类(需要在manifest文件中配置)

/*** 一个定时任务** 方案:使用前台服务去执行网络请求,定时发送广播,然后在广播接收器中重新启动服务,实现循环后台服务。*/
public class RecordService extends Service {private CurPosUtil curPosUtil;/*** 每30秒更新一次数据*/private static final int ONE_Miniute= 30 * 1000;private static final int PENDING_REQUEST=0;int count = 0;public RecordService() {}@Overridepublic void onCreate() {super.onCreate();curPosUtil = new CurPosUtil(getApplicationContext());LogUtil.writerLog("RecordService onCreate");if (Build.VERSION.SDK_INT >=    Build.VERSION_CODES.O) {String NOTIFICATION_CHANNEL_ID = "package_name";String channelName = "My Background Service";NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,channelName, NotificationManager.IMPORTANCE_LOW);NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);manager.createNotificationChannel(channel);Notification notification = new Notification.Builder(this,NOTIFICATION_CHANNEL_ID).setSmallIcon(R.drawable.ic_dial_icon)  // the status icon.setWhen(System.currentTimeMillis())  // the time stamp.setContentText("定时服务正在运行")  // the contents of the entry.build();startForeground(2, notification);}}/*** 调用Service都会执行到该方法*/@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {LogUtil.writerLog("RecordService:  onStartCommand");// 这里模拟后台操作initPos();return super.onStartCommand(intent, flags, startId);}private void initPos() {curPosUtil = new CurPosUtil(this);curPosUtil.getCurPos(new CurPosUtil.CurPosCallback() {@Overridepublic void getCurPos(double s, double s1, String s2) {LogUtil.writerLog(DateUtil.timeToDate(String.valueOf(System.currentTimeMillis())));LogUtil.writerLog("getCurPos: " + s + " " + s1 + " " + s2);commonLogin(s + " " + s1 + " " + s2);}});}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");}public void commonLogin(String position) {RetrofitHelper.getInstance().login(position, "", "", "","", "", "", "").subscribe(new Observer<Boolean>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Boolean aBoolean) {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onComplete() {}});}
}

(6)activity中启动周期任务,周期15分钟循环执行

 PeriodicWorkRequest.Builder request =new PeriodicWorkRequest.Builder(SimpleWorker.class, 15, TimeUnit.MINUTES).addTag("simpleTask");LogUtil.writerLog(DateUtil.timeToDate(String.valueOf(System.currentTimeMillis())));LogUtil.writerLog("点击执行task");WorkManager.getInstance().enqueue(request.build() );

(7)LogUtil工具类,输出日志到文件,方便定位

/*** 日志工具,输出日志到文件*/
public class LogUtil {/*** 路径 "/data/data/com包名/files/backLogTest"** @param msg 需要打印的内容*/public static void writerLog(String msg) {Log.d("baorant", msg);// 保存到的文件路径final String filePath = App.getContext().getFilesDir().getPath();FileWriter fileWriter;BufferedWriter bufferedWriter = null;try {// 创建文件夹File dir = new File(filePath, "backLogTest");if (!dir.exists()) {dir.mkdir();}// 创建文件File file = new File(dir, "lowTemperature.txt");if (!file.exists()) {file.createNewFile();}// 写入日志文件fileWriter = new FileWriter(file, true);bufferedWriter = new BufferedWriter(fileWriter);bufferedWriter.write( msg + "=======时间 :"+ getCurrentTime()+ "\n");bufferedWriter.close();} catch (Exception e) {e.printStackTrace();} finally {if (bufferedWriter != null) {try {bufferedWriter.close();} catch (IOException e) {e.printStackTrace();}}}}private static String getCurrentTime() {Calendar calendar = Calendar.getInstance();@SuppressLint("SimpleDateFormat")SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return  sdf.format(calendar.getTime());}
}

问题总结

运行结果如下:
在这里插入图片描述
在这里插入图片描述
如结果所示,基于该方案可以实现APP在后台,周期循环获取位置信息并进行上报,有兴趣的同学可以进一步深入研究。

相关文章:

安卓开发后台应用周期循环获取位置信息上报服务器

问题背景 最近有需求&#xff0c;在APP启动后&#xff0c;退到后台&#xff0c;还要能实现周期获取位置信息上报服务器&#xff0c;研究了一下实现方案。 问题分析 一、APP退到后台后网络请求实现 APP退到后台后&#xff0c;实现周期循环发送网络请求。目前尝试了两种方案是…...

为什么你的独立站有流量没转化?如何做诊断检查?

新店的创业初期&#xff0c;即使网站有流量&#xff0c;但是销售额为零的情况也常有发生。如果你确定流量是高质量的&#xff0c;寻找阻止潜在客户购买的具体因素可能会感到困难重重。 从“立即购买”按钮的色彩选择这样的细节&#xff0c;到构建品牌故事这样的大计划&#xf…...

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程 文章目录 【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程前言确定版本对应关系源码编译安装Pytorch3d总结 前言 本人windows10下使用【Code for Neural Reflectance Surfaces (NeRS)】算法时需要搭…...

【算法和数据结构】257、LeetCode二叉树的所有路径

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;首先看这道题的输出结果&#xff0c;是前序遍历。然后需要找到从根节点到叶子节点的所有路径&#xff…...

yolov5的后处理解析

由于最近实习项目使用到了yolov5&#xff0c; 发现对yolov5的后处理部分不太熟悉&#xff0c;为防止忘记&#xff0c;这里简单做个记录。 在yolov5里&#xff0c;利用FPN特征金字塔&#xff0c;可以得到三个加强特征层&#xff0c;每一个特征层上每一个特征点存在3个先验框&am…...

Java中注解应用场景

1.Parameter注解 Parameter(names "-browser", description "browser name, supported scope [chrome]", required true) Param注解的用法解析_parameter_fFee-ops的博客-CSDN博客 Public User selectUser(param(“userName”) String name, param(“…...

verilog

数据类型 reg reg [3:0] counter; counter是一个寄存器&#xff0c;这个寄存器有4bit大小&#xff1b; reg [3:0] byte1 [7:0]; 有8个寄存器&#xff0c;每个4bit大小&#xff1b; wire 有符号整数 interge 无符号 reg clk_temp (小数)verilog中称实数…...

基于springboot+mybatis+vue进销存管理信息系统

基于springbootmybatisvue进销存管理信息系统 一、系统介绍二、功能展示1.个人中心2.企业信息管理3.商品信息管理4.客户信息管理5.入库记录管理6.出库记录管理7.出库记录管理8.操作日志管理9.库存盘点管理 四、获取源码 一、系统介绍 系统主要功能&#xff1a; 普通用户&#…...

Keepalived 在CentOS安装

下载 有两种下载方式&#xff0c;一种为yum源下载&#xff0c;另一种通过源代码下载&#xff0c;本文章使用源代码编译下载。 官网下载地址&#xff1a;https://www.keepalived.org/download.html wget https://www.keepalived.org/software/keepalived-2.0.20.tar.gz --no-…...

Lua语法学习

Lua 文章目录 Lua变量数据类型nilbooleanstringtable 循环if函数运算符Table -- Events local StateEvents ReplicatedStorage:WaitForChild("StateEvents"); local AddMoneyEvent StateEvents:WaitForChild("AddMoneyEvent");AddMoneyEvent:FireServer(…...

【Ajax】笔记-jsonp实现原理

JSONP JSONP是什么 JSONP(JSON With Padding),是一个非官方的跨域解决方案&#xff0c;纯粹凭借程序员的聪明才智开发出来的&#xff0c;只支持get请求。JSONP 怎么工作的&#xff1f; 在网页有一些标签天生具有跨域能力&#xff0c;比如&#xff1a;img link iframe script. …...

LLM - Chinese-Llama-2-7b 初体验

目录 一.引言 二.模型下载 三.快速测试 四.训练数据 五.总结 一.引言 自打 LLama-2 发布后就一直在等大佬们发布 LLama-2 的适配中文版&#xff0c;也是这几天蹲到了一版由 LinkSoul 发布的 Chinese-Llama-2-7b&#xff0c;其共发布了一个常规版本和一个 4-bit 的量化版本…...

transformer代码注解

其中代码均来自李沐老师的动手学pytorch中。 class PositionWiseFFN(nn.Module):ffn_num_inputs 4ffn_num_hiddens 4ffn_num_outputs 8def __init__(self,ffn_num_inputs,ffn_num_hiddens,ffn_num_outputs):super(PositionWiseFFN,self).__init__()self.dense1 nn.Linear(ffn…...

【产品经理】高阶产品如何处理需求?(3方法论+2案例+1清单)

不管你是萌新小白&#xff0c;还是工作了几年的“老油条”&#xff0c;需求一直是产品经理工作的重点。只不过&#xff0c;不同年限的产品经理需要面对的需求大有不同&#xff0c;对能力的要求更高。 不知你是否遇过以下问题&#xff1f; 你接手一个项目后&#xff0c;不知从何…...

Neo4j数据库中导入CSV示例数据

本文简要介绍Neo4j数据库以及如何从CSV文件中导入示例数据&#xff0c;方便我们快速学习测试图数据库。首先介绍简单数据模型以及基本图查询概念&#xff0c;然后通过LOAD CSV命令导入数据&#xff0c;生成节点和关系。 环境准备 读者可以快速安装Neo4j Desktop&#xff0c;启…...

第四章 No.1树状数组的原理与使用

文章目录 应用问题原理树状数组练习题241. 楼兰图腾242. 一个简单的整数问题243. 一个简单的整数问题2244. 谜一样的牛 线段树的反面&#xff1a;树状数组原理复杂&#xff0c;实现简单 应用问题 支持两个操作&#xff1a;快速求前缀和任意地修改某个数&#xff0c;时间复杂度…...

mysql(五)主从配置

目录 前言 一、MySQL Replication概述 二、MySQL复制类型 三、部署MySQL主从异步复制 总结 前言 为了实现MySQL的读写分离&#xff0c;可以使用MySQL官方提供的工具和技术&#xff0c;如MySQL Replication&#xff08;复制&#xff09;、MySQL Group Replication&#xff08;组…...

扫地机语音提示芯片,智能家居语音交互首选方案,WT588F02B-8S

智能家居已经成为现代家庭不可或缺的一部分&#xff0c;而语音交互技术正是智能家居的核心。在智能家居设备中&#xff0c;扫地机无疑是最受欢迎的产品之一。然而&#xff0c;要实现一个更智能的扫地机&#xff0c;需要一颗语音提示芯片&#xff0c;以提供高质量的语音交互体验…...

ChatGPT | 分割Word文字及表格,优化文本分析

知识库读取Word内容时&#xff0c;由于embedding切片操作&#xff0c;可能会出现表格被分割成多个切片的情况。这种切片方式可能导致“列名栏”和“内容栏”之间的Y轴关系链断裂&#xff0c;从而无法准确地确定每一列的数据对应关系&#xff0c;从而使得无法准确知道每一列的数…...

基于JavaSE的手机库存管理系统

1、项目背景 基于JavaSE完成如下需求&#xff1a; 功能需求&#xff1a; 1、查询库存量 2、可以修改库存中不同品牌手机的个数 3、退出系统 实现步骤&#xff1a; 1、把List当做库房 2、把手机存放在库房中 3、使用封装的方法区操作仓库中的手机 2、项目知识点 面向对象 集合…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...