城市网站建设,网站开发的专业能力,怎么查什么时候做的网站,16岁的做兼职在什么网站好问题背景
最近有需求#xff0c;在APP启动后#xff0c;退到后台#xff0c;还要能实现周期获取位置信息上报服务器#xff0c;研究了一下实现方案。
问题分析
一、APP退到后台后网络请求实现 APP退到后台后#xff0c;实现周期循环发送网络请求。目前尝试了两种方案是…问题背景
最近有需求在APP启动后退到后台还要能实现周期获取位置信息上报服务器研究了一下实现方案。
问题分析
一、APP退到后台后网络请求实现 APP退到后台后实现周期循环发送网络请求。目前尝试了两种方案是OK如下 1AlarmManager 前台服务 广播的方案可以正常实现大体思路是启动一个前台服务使用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)2manifest文件中增加申请权限 uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / !-- 这个权限用于访问GPS定位 --uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / !-- 用于访问wifi网络信息wifi信息会用于进行网络定位 --uses-permission android:nameandroid.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);4work类去执行前台服务 /*** work类执行定时任务*/
public class SimpleWorker extends Worker {private CurPosUtil curPosUtil;public SimpleWorker(NonNull Context context, NonNull WorkerParameters workerParams) {super(context, workerParams);}NonNullOverridepublic 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);}
}5RecordService前台服务类需要在manifest文件中配置
/*** 一个定时任务** 方案使用前台服务去执行网络请求定时发送广播然后在广播接收器中重新启动服务实现循环后台服务。*/
public class RecordService extends Service {private CurPosUtil curPosUtil;/*** 每30秒更新一次数据*/private static final int ONE_Miniute 30 * 1000;private static final int PENDING_REQUEST0;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 ObserverBoolean() {Overridepublic void onSubscribe(Disposable d) {}Overridepublic void onNext(Boolean aBoolean) {}Overridepublic void onError(Throwable e) {}Overridepublic void onComplete() {}});}
}6activity中启动周期任务周期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() );7LogUtil工具类输出日志到文件方便定位
/*** 日志工具输出日志到文件*/
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在后台周期循环获取位置信息并进行上报有兴趣的同学可以进一步深入研究。