From 566e84f53f2ad9e90812440bfb0c5c360aea55c0 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Tue, 4 Nov 2025 20:56:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90=E4=BC=A0?= =?UTF-8?q?=E6=84=9F=E5=99=A8=E9=99=80=E8=9E=BA=E4=BB=AA=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=EF=BC=8C=E4=B8=8E=E6=8E=A5=E6=94=B6=E5=99=A8=E6=8E=A5=E6=94=B6?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- positions/build.properties | 4 +- positions/src/main/AndroidManifest.xml | 48 +- .../receivers/MotionStatusReceiver.java | 421 ++++++++++++++---- .../positions/services/MainService.java | 204 +++++---- 4 files changed, 472 insertions(+), 205 deletions(-) diff --git a/positions/build.properties b/positions/build.properties index c367a46..f7130a2 100644 --- a/positions/build.properties +++ b/positions/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Tue Oct 28 20:03:59 HKT 2025 +#Tue Nov 04 12:54:59 GMT 2025 stageCount=18 libraryProject= baseVersion=15.0 publishVersion=15.0.17 -buildCount=0 +buildCount=20 baseBetaVersion=15.0.18 diff --git a/positions/src/main/AndroidManifest.xml b/positions/src/main/AndroidManifest.xml index 72ceca0..db82105 100644 --- a/positions/src/main/AndroidManifest.xml +++ b/positions/src/main/AndroidManifest.xml @@ -3,24 +3,24 @@ xmlns:android="http://schemas.android.com/apk/res/android" package="cc.winboll.studio.positions"> - - - - - - - - - + + + + + + + + + @@ -59,22 +59,28 @@ android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/> - + - + - + + + + + + + + + + - - - - - - diff --git a/positions/src/main/java/cc/winboll/studio/positions/receivers/MotionStatusReceiver.java b/positions/src/main/java/cc/winboll/studio/positions/receivers/MotionStatusReceiver.java index c3f6e89..7ff5e8b 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/receivers/MotionStatusReceiver.java +++ b/positions/src/main/java/cc/winboll/studio/positions/receivers/MotionStatusReceiver.java @@ -9,116 +9,353 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.text.TextUtils; import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.positions.services.MainService; import cc.winboll.studio.positions.utils.ServiceUtil; /** * 运动状态监听Receiver - * 功能:接收运动状态广播,控制GPS权限申请与GPS监听开关 + * 功能:1.持续监听传感器(不关闭) 2.每5秒计算运动状态 3.按状态切换GPS模式(实时/30秒定时) */ -public class MotionStatusReceiver extends BroadcastReceiver { - public static final String TAG = "MotionStatusReceiver"; +public class MotionStatusReceiver extends BroadcastReceiver implements SensorEventListener { + public static final String TAG = "MotionStatusReceiver"; - // 运动状态广播Action(需与运动状态发送方保持一致,如传感器服务) - public static final String ACTION_MOTION_STATUS = "cc.winboll.studio.positions.ACTION_MOTION_STATUS"; - // 运动状态Extra键:0=静止/低运动,1=行走/高运动 - public static final String EXTRA_MOTION_STATUS = "EXTRA_MOTION_STATUS"; - // 静止时GPS定时获取间隔(单位:分钟,可配置) - public static final long GPS_STATIC_INTERVAL = 1; + // 广播Action + public static final String ACTION_MOTION_STATUS_RECEIVER = "cc.winboll.studio.positions.receivers.MotionStatusReceiver"; + public static final String EXTRA_SENSORS_ENABLE = "EXTRA_SENSORS_ENABLE"; + // 传感器启动状态标志位 + boolean mIsSensorsEnable = false; + // 运动状态常量 + private static final int MOTION_STATUS_STATIC = 0; // 静止/低运动 + private static final int MOTION_STATUS_WALKING = 1; // 行走/高速运动 + // 配置参数(按需求调整) + private static final float ACCELEROMETER_THRESHOLD = 0.8f; // 加速度阈值 + private static final float GYROSCOPE_THRESHOLD = 0.5f; // 陀螺仪阈值 + private static final long STATUS_CALC_INTERVAL = 5000; // 运动状态计算间隔(5秒) + private static final long GPS_STATIC_INTERVAL = 30; // 静止时GPS间隔(30秒) + // 核心对象 + private volatile SensorManager mSensorManager; + private Sensor mAccelerometer; + private Sensor mGyroscope; + private volatile boolean mIsSensorListening = false; // 传感器是否持续监听 + private int mCurrentMotionStatus = MOTION_STATUS_STATIC; // 当前运动状态 + private Handler mMainHandler; // 主线程Handler(用于定时计算) + private Context mBroadcastContext; // 广播上下文 + // 传感器数据缓存(用于5秒内数据汇总,避免单次波动误判) + private float mAccelMax = 0f; // 5秒内加速度最大值 + private float mGyroMax = 0f; // 5秒内陀螺仪最大值 - @Override - public void onReceive(Context context, Intent intent) { - if (context == null || intent == null || !TextUtils.equals(intent.getAction(), ACTION_MOTION_STATUS)) { - LogUtils.w(TAG, "无效广播:Action不匹配或上下文为空"); - return; - } + @Override + public void onReceive(Context context, Intent intent) { - // 1. 获取运动状态(0=静止/低运动,1=行走/高运动) - int motionStatus = intent.getIntExtra(EXTRA_MOTION_STATUS, 0); - LogUtils.d(TAG, "接收运动状态:" + (motionStatus == 1 ? "行走中" : "静止/低运动")); + LogUtils.d(TAG, "===== 接收器启动:onReceive() 开始执行 ====="); + this.mBroadcastContext = context; + mMainHandler = new Handler(Looper.getMainLooper()); - // 2. 绑定并获取MainService实例(确保服务已启动) - MainService mainService = getMainService(context); - if (mainService == null) { - LogUtils.e(TAG, "MainService未启动,无法控制GPS状态"); - return; - } + if (TextUtils.equals(intent.getAction(), ACTION_MOTION_STATUS_RECEIVER)) { + boolean isSettingEnable = intent.getBooleanExtra(EXTRA_SENSORS_ENABLE, false); + if (mIsSensorsEnable == false && isSettingEnable == true) { + mIsSensorsEnable = true; + // 1. 初始化传感器(必执行) + initSensors(); + - // 3. 根据运动状态处理GPS逻辑 - if (motionStatus == 1) { - // 3.1 行走中:申请GPS权限(若未授予)+ 开启持续GPS监听 - handleWalkingStatus(mainService, context); - } else { - // 3.2 静止/低运动:关闭持续GPS监听 + 启动定时GPS获取 - handleStaticStatus(mainService); - } - } + if (mAccelerometer == null || mGyroscope == null) { + LogUtils.e(TAG, "设备缺少加速度/陀螺仪,无法持续监听"); + cleanResources(false); // 传感器不可用才清理 + return; + } - /** - * 处理行走状态:申请GPS权限+开启持续GPS监听 - */ - private void handleWalkingStatus(MainService mainService, Context context) { - // 检查GPS权限(Android 6.0+动态权限) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && - context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { - // 发送权限申请广播(由Activity接收并发起申请,Receiver无法直接申请权限) - Intent permissionIntent = new Intent("cc.winboll.studio.positions.ACTION_REQUEST_GPS_PERMISSION"); - permissionIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - context.sendBroadcast(permissionIntent); - LogUtils.d(TAG, "行走中:GPS权限未授予,已发送权限申请广播"); - return; - } + // 2. 校验参数 + if (context == null || intent == null) { + LogUtils.d(TAG, "onReceive():无效参数,终止处理"); + cleanResources(false); + return; + } + LogUtils.d(TAG, "onReceive():接收到广播Action=" + intent.getAction()); - // 权限已授予:开启持续GPS监听(调用MainService原有方法) - if (!mainService.isGpsListening()) { // 需在MainService中新增isGpsListening()方法 - mainService.startGpsLocation(); - LogUtils.d(TAG, "行走中:已开启持续GPS监听"); - } + // 3. 启动持续传感器监听(核心:不关闭,重复调用无影响) + startSensorListening(); - // 停止静止时的GPS定时任务(避免重复获取) - mainService.stopGpsStaticTimer(); - } - - /** - * 处理静止状态:关闭持续GPS监听+启动定时GPS获取 - */ - private void handleStaticStatus(MainService mainService) { - // 关闭持续GPS监听(避免耗电) - if (mainService.isGpsListening()) { - mainService.stopGpsLocation(); - LogUtils.d(TAG, "静止中:已关闭持续GPS监听"); - } - - // 启动定时GPS获取(获取一次后关闭,间隔GPS_STATIC_INTERVAL分钟) - mainService.startGpsStaticTimer(GPS_STATIC_INTERVAL); - } - - /** - * 获取MainService实例(通过绑定服务或单例,确保线程安全) - */ - private MainService getMainService(Context context) { - // 方式1:若MainService单例有效,直接获取(推荐) - MainService singleton = MainService.getInstance(context); - if (singleton != null && singleton.isServiceRunning()) { - return singleton; - } - - // 方式2:若单例无效,尝试绑定服务(备用,需处理绑定回调) - if (!ServiceUtil.isServiceAlive(context, MainService.class.getName())) { - // 启动服务(若未运行) - context.startService(new Intent(context, MainService.class)); - // 等待服务启动(短延时,实际项目建议用ServiceConnection异步绑定) - try { - Thread.sleep(500); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + // 4. 启动5秒定时计算运动状态(核心:持续触发状态判断) + startStatusCalcTimer(); } } - return MainService.getInstance(context); - } + + + // 5. 处理外部广播触发(可选,保留外部控制能力) +// if (TextUtils.equals(intent.getAction(), ACTION_MOTION_STATUS_RECEIVER)) { +// int motionStatus = intent.getIntExtra(EXTRA_MOTION_STATUS, MOTION_STATUS_STATIC); +// String statusDesc = motionStatus == MOTION_STATUS_WALKING ? "高速运动" : "静止/低运动"; +// LogUtils.d(TAG, "外部广播触发,强制设置运动状态:" + statusDesc); +// mCurrentMotionStatus = motionStatus; +// handleMotionStatus(mCurrentMotionStatus); // 立即执行GPS切换 +// } + } + + /** + * 初始化传感器(持续监听,复用实例) + */ + private void initSensors() { + LogUtils.d(TAG, "initSensors():初始化传感器"); + if (mSensorManager != null || mBroadcastContext == null) return; + + mSensorManager = (SensorManager) mBroadcastContext.getSystemService(Context.SENSOR_SERVICE); + if (mSensorManager == null) { + LogUtils.e(TAG, "设备不支持传感器服务"); + return; + } + // 获取传感器实例(持续复用,不销毁) + mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); + + LogUtils.d(TAG, "传感器初始化结果:加速度=" + (mAccelerometer != null) + ",陀螺仪=" + (mGyroscope != null)); + } + + /** + * 启动传感器持续监听(核心:不关闭,注册一次一直生效) + */ + private void startSensorListening() { + if (mSensorManager == null || mAccelerometer == null || mGyroscope == null) return; + + if (!mIsSensorListening) { + // 注册传感器监听(持续生效,直到服务销毁才注销) + mSensorManager.registerListener( + this, + mAccelerometer, + SensorManager.SENSOR_DELAY_NORMAL, // 正常延迟,平衡性能与精度 + mMainHandler + ); + mSensorManager.registerListener( + this, + mGyroscope, + SensorManager.SENSOR_DELAY_NORMAL, + mMainHandler + ); + mIsSensorListening = true; + LogUtils.d(TAG, "startSensorListening():传感器持续监听已启动(不关闭)"); + } + } + + /** + * 启动5秒定时计算运动状态(核心:周期性汇总传感器数据) + */ + private void startStatusCalcTimer() { + if (mMainHandler == null) return; + + // 移除旧任务(避免重复注册) + mMainHandler.removeCallbacks(mStatusCalcRunnable); + // 启动定时任务(每5秒执行一次) + mMainHandler.postDelayed(mStatusCalcRunnable, STATUS_CALC_INTERVAL); + LogUtils.d(TAG, "startStatusCalcTimer():5秒运动状态计算定时器已启动"); + } + + /** + * 运动状态计算任务(5秒执行一次) + */ + private final Runnable mStatusCalcRunnable = new Runnable() { + @Override + public void run() { + // 1. 基于5秒内缓存的最大传感器数据判断状态 + boolean isHighMotion = (mAccelMax > ACCELEROMETER_THRESHOLD) && (mGyroMax > GYROSCOPE_THRESHOLD); + int newMotionStatus = isHighMotion ? MOTION_STATUS_WALKING : MOTION_STATUS_STATIC; + + // 2. 状态变化时才处理(避免频繁切换GPS) + if (newMotionStatus != mCurrentMotionStatus) { + mCurrentMotionStatus = newMotionStatus; + String statusDesc = isHighMotion ? "高速运动" : "静止/低运动"; + LogUtils.d(TAG, "运动状态更新(5秒计算):" + statusDesc + + "(加速度最大值=" + mAccelMax + ",陀螺仪最大值=" + mGyroMax + ")"); + handleMotionStatus(newMotionStatus); // 切换GPS模式 + } else { + LogUtils.d(TAG, "运动状态无变化(5秒计算):" + (isHighMotion ? "高速运动" : "静止/低运动")); + } + + // 3. 重置传感器数据缓存,准备下一个5秒周期 + mAccelMax = 0f; + mGyroMax = 0f; + + // 4. 循环执行定时任务(核心:持续计算) + mMainHandler.postDelayed(this, STATUS_CALC_INTERVAL); + } + }; + + /** + * 传感器数据变化回调(核心:实时缓存最大数据) + */ + @Override + public void onSensorChanged(SensorEvent event) { + if (event == null) return; + + // 实时缓存5秒内的最大传感器数据(避免单次波动误判) + switch (event.sensor.getType()) { + case Sensor.TYPE_ACCELEROMETER: + float accelTotal = Math.abs(event.values[0]) + Math.abs(event.values[1]) + Math.abs(event.values[2]); + if (accelTotal > mAccelMax) mAccelMax = accelTotal; // 缓存最大值 + LogUtils.d(TAG, "加速度传感器实时数据:合值=" + accelTotal + "(当前5秒最大值=" + mAccelMax + ")"); + break; + case Sensor.TYPE_GYROSCOPE: + float gyroTotal = Math.abs(event.values[0]) + Math.abs(event.values[1]) + Math.abs(event.values[2]); + if (gyroTotal > mGyroMax) mGyroMax = gyroTotal; // 缓存最大值 + LogUtils.d(TAG, "陀螺仪实时数据:合值=" + gyroTotal + "(当前5秒最大值=" + mGyroMax + ")"); + break; + } + } + + /** + * 处理运动状态(核心:按状态切换GPS模式) + */ + private void handleMotionStatus(int motionStatus) { + LogUtils.d(TAG, "handleMotionStatus():开始处理运动状态,切换GPS模式"); + if (mBroadcastContext == null) { + LogUtils.w(TAG, "上下文为空,无法处理GPS"); + return; + } + + MainService mainService = getMainService(); + if (mainService == null) { + LogUtils.e(TAG, "MainService未启动,GPS控制失败"); + return; + } + + if (motionStatus == MOTION_STATUS_WALKING) { + // 高速运动:启动GPS实时更新(2秒/1米) + handleHighMotionGPS(mainService); + } else { + // 静止/低运动:启动GPS30秒定时更新 + handleStaticGPS(mainService); + } + } + + /** + * 高速运动GPS处理:实时更新 + */ + private void handleHighMotionGPS(MainService mainService) { + // 动态权限判断(Android 6.0+) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + mBroadcastContext.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + sendPermissionRequestBroadcast(); + return; + } + + // 启动实时GPS(已启动则不重复操作) + if (!mainService.isGpsListening()) { + mainService.startGpsLocation(); // 实时更新(2秒/1米) + mainService.stopGpsStaticTimer(); // 停止定时GPS + LogUtils.d(TAG, "高速运动:已启动GPS实时更新"); + } + } + + /** + * 静止/低运动GPS处理:30秒定时更新 + */ + private void handleStaticGPS(MainService mainService) { + // 停止实时GPS(已停止则不重复操作) + if (mainService.isGpsListening()) { + mainService.stopGpsLocation(); // 停止实时更新 + LogUtils.d(TAG, "静止/低运动:已停止GPS实时更新"); + } + + // 启动30秒定时GPS(已启动则不重复操作) + mainService.startGpsStaticTimer(GPS_STATIC_INTERVAL); // 30秒一次 + LogUtils.d(TAG, "静止/低运动:已启动GPS30秒定时更新"); + } + + /** + * 获取MainService实例(复用逻辑) + */ + private MainService getMainService() { + if (mBroadcastContext == null) return null; + + // 优先获取单例 + MainService singleton = MainService.getInstance(mBroadcastContext); + if (singleton != null && singleton.isServiceRunning()) { + return singleton; + } + + // 启动服务并重试 + if (!ServiceUtil.isServiceAlive(mBroadcastContext, MainService.class.getName())) { + mBroadcastContext.startService(new Intent(mBroadcastContext, MainService.class)); + try { + Thread.sleep(500); // 等待服务启动 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + return MainService.getInstance(mBroadcastContext); + } + + /** + * 发送GPS权限申请广播(Receiver无法直接申请) + */ + private void sendPermissionRequestBroadcast() { + Intent permissionIntent = new Intent("cc.winboll.studio.positions.ACTION_REQUEST_GPS_PERMISSION"); + permissionIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + mBroadcastContext.sendBroadcast(permissionIntent); + LogUtils.d(TAG, "GPS权限缺失,已发送申请广播"); + } + + /** + * 资源清理(核心:传感器不关闭,仅清理Handler和上下文) + * @param isForceStopSensor 是否强制停止传感器(仅服务销毁时传true) + */ + private void cleanResources(boolean isForceStopSensor) { + // 1. 停止定时计算任务 + if (mMainHandler != null) { + mMainHandler.removeCallbacksAndMessages(null); + mMainHandler = null; + LogUtils.d(TAG, "cleanResources():已停止运动状态计算定时器"); + } + + // 2. 强制停止传感器(仅当外部触发销毁时执行,正常情况不关闭) + if (isForceStopSensor && mSensorManager != null && mIsSensorListening) { + mSensorManager.unregisterListener(this); + mIsSensorListening = false; + LogUtils.d(TAG, "cleanResources():已强制停止传感器监听"); + } + + // 3. 置空上下文(避免内存泄漏) + mBroadcastContext = null; + } + + /** + * 传感器精度变化回调(日志监控) + */ + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + String sensorType = sensor.getType() == Sensor.TYPE_ACCELEROMETER ? "加速度" : "陀螺仪"; + String accuracyDesc = getAccuracyDesc(accuracy); + LogUtils.d(TAG, sensorType + "传感器精度变化:" + accuracyDesc); + } + + /** + * 传感器精度描述转换 + */ + private String getAccuracyDesc(int accuracy) { + switch (accuracy) { + case SensorManager.SENSOR_STATUS_ACCURACY_HIGH: return "高"; + case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM: return "中"; + case SensorManager.SENSOR_STATUS_ACCURACY_LOW: return "低"; + case SensorManager.SENSOR_STATUS_UNRELIABLE: return "不可靠"; + default: return "未知"; + } + } + + /** + * 补充:Receiver销毁时强制清理(需在MainService注销时调用) + */ + public void forceCleanResources() { + cleanResources(true); // 强制停止传感器 + } } diff --git a/positions/src/main/java/cc/winboll/studio/positions/services/MainService.java b/positions/src/main/java/cc/winboll/studio/positions/services/MainService.java index 773d288..e1c7293 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/services/MainService.java +++ b/positions/src/main/java/cc/winboll/studio/positions/services/MainService.java @@ -9,6 +9,7 @@ import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.location.Location; @@ -24,6 +25,7 @@ import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.positions.models.PositionModel; import cc.winboll.studio.positions.models.PositionTaskModel; +import cc.winboll.studio.positions.receivers.MotionStatusReceiver; import cc.winboll.studio.positions.utils.AppConfigsUtil; import cc.winboll.studio.positions.utils.DistanceCalculatorUtil; import cc.winboll.studio.positions.utils.NotificationUtil; @@ -43,10 +45,7 @@ public class MainService extends Service { public static final String EXTRA_IS_SETTING_TO_ENABLE = "EXTRA_IS_SETTING_TO_ENABLE"; // ---------------------- 定时器相关变量 ---------------------- - private ScheduledExecutorService taskCheckTimer; // 任务校验定时器 - private static final long TASK_CHECK_INTERVAL = 1; // 定时间隔(1分钟) - private static final long TASK_CHECK_INIT_DELAY = 1; // 初始延迟(1分钟) - // 新增:静止时GPS定时任务变量(Java 7 显式声明) + // 静止时GPS定时任务变量(Java 7 显式声明) private ScheduledExecutorService gpsStaticTimer; // 静止时GPS定时获取线程池 private volatile boolean isGpsListening = false; // GPS是否处于持续监听状态 private static final long GPS_STATIC_DURATION = 3; // 静止时GPS单次获取超时时间(秒) @@ -92,47 +91,15 @@ public class MainService extends Service { private static volatile MainService sInstance; private static Context sAppContext; + // 核心:运动状态Receiver(动态注册/注销,Java 7 显式声明) + private MotionStatusReceiver mMotionStatusReceiver; + private IntentFilter mMotionStatusFilter; + // ========================================================================= - // 定时器初始化方法(任务校验+静止GPS定时) + // 静止GPS定时任务方法(Java 7 语法) // ========================================================================= - /*private void initTaskCheckTimer() { - // 先销毁旧定时器(避免重复创建) - if (taskCheckTimer != null && !taskCheckTimer.isShutdown()) { - taskCheckTimer.shutdown(); - } - - // 创建单线程定时器(任务串行执行) - taskCheckTimer = Executors.newSingleThreadScheduledExecutor(); - taskCheckTimer.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - LogUtils.d(TAG, "定时任务触发:开始校验任务(间隔1分钟)"); - DistanceCalculatorUtil.getInstance(MainService.this).checkAllTaskTriggerCondition(MainService._mCurrentGpsPosition); - } - }, TASK_CHECK_INIT_DELAY, TASK_CHECK_INTERVAL, TimeUnit.MINUTES); - - LogUtils.d(TAG, "任务校验定时器已启动(间隔:" + TASK_CHECK_INTERVAL + "分钟)"); - }*/ - - /*private void destroyTaskCheckTimer() { - if (taskCheckTimer != null && !taskCheckTimer.isShutdown()) { - taskCheckTimer.shutdown(); // 优雅关闭 - try { - if (!taskCheckTimer.awaitTermination(1, TimeUnit.SECONDS)) { - taskCheckTimer.shutdownNow(); // 强制关闭 - } - } catch (InterruptedException e) { - taskCheckTimer.shutdownNow(); - Thread.currentThread().interrupt(); // 恢复中断状态 - } finally { - taskCheckTimer = null; - LogUtils.d(TAG, "任务校验定时器已销毁"); - } - } - }*/ - - // 新增:启动静止时GPS定时获取(Java 7 语法,无Lambda) + // 启动静止时GPS定时获取 public void startGpsStaticTimer(long interval) { // 先销毁旧定时器(避免重复创建) stopGpsStaticTimer(); @@ -150,7 +117,7 @@ public class MainService extends Service { LogUtils.d(TAG, "静止时GPS定时任务已启动(间隔:" + interval + "分钟)"); } - // 新增:停止静止时GPS定时任务 + // 停止静止时GPS定时任务 public void stopGpsStaticTimer() { if (gpsStaticTimer != null && !gpsStaticTimer.isShutdown()) { gpsStaticTimer.shutdown(); @@ -168,7 +135,7 @@ public class MainService extends Service { } } - // 新增:单次GPS获取(获取后关闭监听,Java 7 匿名内部类) + // 单次GPS获取(获取后关闭监听,Java 7 匿名内部类) private void startSingleGpsRetrieve() { if (!checkGpsReady()) { LogUtils.w(TAG, "单次GPS获取:GPS未就绪,跳过"); @@ -379,7 +346,7 @@ public class MainService extends Service { // ========================================================================= - // 原有基础方法(Java 7 语法适配) + // 服务基础方法(核心调整:动态注册/注销MotionStatusReceiver) // ========================================================================= public static synchronized MainService getInstance(Context context) { if (sInstance == null) { @@ -418,15 +385,19 @@ public class MainService extends Service { mMyServiceConnection = new MyServiceConnection(); } + // 初始化GPS监听(仅初始化,不启动) + //initGpsLocationListener(); + if (mAppConfigsUtil.isEnableMainService(true)) { run(); // 启动服务核心逻辑 } } + // 服务核心运行方法(调整:启动服务时仅注册Receiver,不启动GPS) public void run() { if (mAppConfigsUtil.isEnableMainService(true)) { if (!_mIsServiceRunning) { - _mIsServiceRunning = true; + _mIsServiceRunning = true; wakeupAndBindAssistant(); // 唤醒并绑定辅助服务 // 启动前台服务 @@ -435,25 +406,70 @@ public class MainService extends Service { startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID, NotificationUtil.createForegroundServiceNotification(this, initialStatus)); - // 初始化GPS相关 + // 初始化LocationManager(仅初始化,不启动GPS) mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); - initGpsLocationListener(); - startGpsLocation(); // 加载本地数据 PositionModel.loadBeanList(MainService.this, mPositionList, PositionModel.class); PositionTaskModel.loadBeanList(MainService.this, mAllTasks, PositionTaskModel.class); + // 初始化运动状态Receiver(动态注册准备) + initMotionStatusReceiver(); + + // 动态注册MotionStatusReceiver(核心:交给Receiver控制GPS) + registerMotionStatusReceiver(); + + Intent triggerIntent = new Intent(MotionStatusReceiver.ACTION_MOTION_STATUS_RECEIVER); + triggerIntent.putExtra(MotionStatusReceiver.EXTRA_SENSORS_ENABLE, true); + sendBroadcast(triggerIntent); + LogUtils.d(TAG, "已发送自主触发广播,唤醒MotionStatusReceiver"); + // 提示与日志 ToastUtils.show(initialStatus); LogUtils.i(TAG, initialStatus); - - // 启动任务校验定时器 - //initTaskCheckTimer(); } } } + // 初始化运动状态Receiver和IntentFilter + private void initMotionStatusReceiver() { + LogUtils.d(TAG, "initMotionStatusReceiver()"); + mMotionStatusReceiver = new MotionStatusReceiver(); + mMotionStatusFilter = new IntentFilter(); + mMotionStatusFilter.addAction(MotionStatusReceiver.ACTION_MOTION_STATUS_RECEIVER); + } + + // 动态注册MotionStatusReceiver + private void registerMotionStatusReceiver() { + LogUtils.d(TAG, "registerMotionStatusReceiver()"); + if (mMotionStatusReceiver != null && mMotionStatusFilter != null) { + try { + registerReceiver(mMotionStatusReceiver, mMotionStatusFilter); + LogUtils.d(TAG, "MotionStatusReceiver 动态注册成功"); + } catch (Exception e) { + LogUtils.e(TAG, "MotionStatusReceiver 注册失败:" + e.getMessage()); + } + } + } + + // + // 动态注销MotionStatusReceiver + // + private void unregisterMotionStatusReceiver() { + if (mMotionStatusReceiver != null) { + try { + unregisterReceiver(mMotionStatusReceiver); + mMotionStatusReceiver.forceCleanResources(); // 新增:强制清理传感器 + LogUtils.d(TAG, "MotionStatusReceiver 注销并强制清理传感器"); + } catch (Exception e) { + LogUtils.e(TAG, "MotionStatusReceiver 注销失败:" + e.getMessage()); + } finally { + mMotionStatusReceiver = null; + mMotionStatusFilter = null; + } + } + } + public boolean isServiceRunning() { return _mIsServiceRunning; } @@ -463,8 +479,12 @@ public class MainService extends Service { super.onDestroy(); sInstance = null; - // 清理资源 - stopGpsLocation(); + // 核心清理:1.注销MotionStatusReceiver 2.关闭GPS 3.停止定时任务 + unregisterMotionStatusReceiver(); // 注销Receiver,避免内存泄漏 + stopGpsLocation(); // 强制关闭GPS监听 + stopGpsStaticTimer(); // 停止静止时GPS定时任务 + + // 其他资源清理 clearAllData(); stopForeground(true); @@ -474,9 +494,7 @@ public class MainService extends Service { mTaskListeners.clear(); } - // 销毁所有定时器与线程池 - //destroyTaskCheckTimer(); - stopGpsStaticTimer(); // 新增:销毁静止时GPS定时任务 + // 销毁线程池 if (distanceExecutor != null && !distanceExecutor.isShutdown()) { distanceExecutor.shutdown(); } @@ -484,8 +502,9 @@ public class MainService extends Service { // 重置状态变量 _mIsServiceRunning = false; isGpsEnabled = false; - isGpsListening = false; // 新增:重置GPS监听状态 + isGpsListening = false; mLocationManager = null; + LogUtils.d(TAG, "MainService 销毁完成,所有资源已清理"); } @@ -500,7 +519,7 @@ public class MainService extends Service { return _mCurrentGpsPosition; } - // 新增:判断GPS是否处于持续监听状态(给Receiver调用) + // 对外提供:判断GPS是否处于持续监听状态(给MotionStatusReceiver调用) public boolean isGpsListening() { return isGpsListening; } @@ -606,10 +625,10 @@ public class MainService extends Service { } // 格式化通知内容 final String gpsStatus = String.format( - "GPS位置:北纬%.4f° 东经%.4f° | 可见位置:%d个", - _mCurrentGpsPosition.getLatitude(), - _mCurrentGpsPosition.getLongitude(), - mVisiblePositionIds.size() + "GPS位置:北纬%.4f° 东经%.4f° | 可见位置:%d个", + _mCurrentGpsPosition.getLatitude(), + _mCurrentGpsPosition.getLongitude(), + mVisiblePositionIds.size() ); // 主线程切换 if (Looper.myLooper() == Looper.getMainLooper()) { @@ -634,7 +653,7 @@ public class MainService extends Service { if (intent != null) { isSettingToEnable = intent.getBooleanExtra(EXTRA_IS_SETTING_TO_ENABLE, false); if (isSettingToEnable) { - run(); // 重启服务核心逻辑 + run(); // 重启服务核心逻辑(重新注册Receiver) } } @@ -669,13 +688,14 @@ public class MainService extends Service { // ========================================================================= - // GPS相关核心方法(Java 7 语法,匿名内部类实现) + // GPS相关核心方法(Java 7 语法,仅保留Receiver调用的启动/停止逻辑) // ========================================================================= public MainService() { distanceExecutor = Executors.newSingleThreadScheduledExecutor(); initGpsLocationListener(); } + // 初始化GPS监听(仅创建Listener,不注册) private void initGpsLocationListener() { LogUtils.d(TAG, "initGpsLocationListener"); mGpsLocationListener = new LocationListener() { @@ -725,8 +745,8 @@ public class MainService extends Service { String statusDesc = "GPS已开启(用户手动打开)"; LogUtils.d(TAG, statusDesc); notifyAllGpsStatusListeners(statusDesc); - updateNotificationGpsStatus("GPS已开启,正在获取位置..."); - startGpsLocation(); + updateNotificationGpsStatus("GPS已开启,等待Receiver控制启动..."); + // 不主动启动GPS,由Receiver根据运动状态控制 } } @@ -734,7 +754,7 @@ public class MainService extends Service { public void onProviderDisabled(String provider) { if (provider.equals(LocationManager.GPS_PROVIDER)) { isGpsEnabled = false; - isGpsListening = false; // 新增:GPS禁用时重置监听状态 + isGpsListening = false; _mCurrentGpsPosition = null; String statusDesc = "GPS已关闭(用户手动关闭)"; LogUtils.w(TAG, statusDesc); @@ -746,10 +766,11 @@ public class MainService extends Service { }; } + // GPS就绪检查(给Receiver调用的GPS操作做前置判断) private boolean checkGpsReady() { // 检查定位权限 isGpsPermissionGranted = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED; + == PackageManager.PERMISSION_GRANTED; // 初始化LocationManager if (mLocationManager == null) { @@ -781,22 +802,23 @@ public class MainService extends Service { return true; } + // 启动GPS持续监听(仅Receiver可调用) public void startGpsLocation() { - if (!checkGpsReady()) { + if (!checkGpsReady() || isGpsListening) { return; } try { // 注册GPS位置更新 mLocationManager.requestLocationUpdates( - LocationManager.GPS_PROVIDER, - GPS_UPDATE_INTERVAL, - GPS_UPDATE_DISTANCE, - mGpsLocationListener, - Looper.getMainLooper() + LocationManager.GPS_PROVIDER, + GPS_UPDATE_INTERVAL, + GPS_UPDATE_DISTANCE, + mGpsLocationListener, + Looper.getMainLooper() ); - // 新增:标记GPS进入持续监听状态 + // 标记GPS进入持续监听状态 isGpsListening = true; // 获取最后已知GPS位置 @@ -820,17 +842,18 @@ public class MainService extends Service { LogUtils.e(TAG, error); notifyAllGpsStatusListeners(error); isGpsPermissionGranted = false; - isGpsListening = false; // 新增:异常时重置监听状态 + isGpsListening = false; updateNotificationGpsStatus("定位权限异常,无法获取GPS"); } catch (Exception e) { String error = "启动GPS失败:" + e.getMessage(); LogUtils.e(TAG, error); notifyAllGpsStatusListeners(error); - isGpsListening = false; // 新增:异常时重置监听状态 + isGpsListening = false; updateNotificationGpsStatus("GPS启动失败,尝试重试..."); } } + // 停止GPS持续监听(仅Receiver可调用) public void stopGpsLocation() { // 校验参数:避免空指针+权限未授予时调用 if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) { @@ -839,12 +862,12 @@ public class MainService extends Service { String tip = "GPS定位已停止(移除监听器)"; LogUtils.d(TAG, tip); notifyAllGpsStatusListeners(tip); - isGpsListening = false; // 新增:停止监听时重置状态 + isGpsListening = false; } catch (Exception e) { String error = "停止GPS失败:" + e.getMessage(); LogUtils.e(TAG, error); notifyAllGpsStatusListeners(error); - isGpsListening = false; // 新增:异常时重置状态 + isGpsListening = false; } } } @@ -857,12 +880,12 @@ public class MainService extends Service { // 格式化通知内容 final String triggerContent = String.format( - "任务触发:%s\n位置:%s\n当前距离:%.1f米(条件:%s%d米)", - task.getTaskDescription(), - bindPos.getMemo(), - currentDistance, - task.isGreaterThan() ? ">" : "<", - task.getDiscussDistance() + "任务触发:%s\n位置:%s\n当前距离:%.1f米(条件:%s%d米)", + task.getTaskDescription(), + bindPos.getMemo(), + currentDistance, + task.isGreaterThan() ? ">" : "<", + task.getDiscussDistance() ); // 更新前台通知 @@ -887,7 +910,7 @@ public class MainService extends Service { // 更新前台通知的GPS状态 void updateNotificationGpsStatus(final String statusText) { if (_mIsServiceRunning) { - // 主线程判断+切换 + // 主线程判断+切换(Java7匿名内部类) if (Looper.myLooper() == Looper.getMainLooper()) { NotificationUtil.updateForegroundServiceStatus(this, statusText); } else { @@ -903,7 +926,7 @@ public class MainService extends Service { // ========================================================================= - // GPS监听通知相关方法(Java 7 语法) + // GPS监听通知相关方法(Java7语法,给外部监听者回调) // ========================================================================= public void notifyAllGpsListeners(PositionModel currentGpsPos) { if (currentGpsPos == null || mGpsListeners.isEmpty()) { @@ -946,7 +969,7 @@ public class MainService extends Service { WeakReference ref = iter.next(); final GpsUpdateListener listener = ref.get(); if (listener != null) { - // 主线程切换,避免UI异常 + // 主线程切换,避免UI异常(Java7匿名Runnable) if (Looper.myLooper() == Looper.getMainLooper()) { listener.onGpsStatusChanged(status); } else { @@ -999,7 +1022,7 @@ public class MainService extends Service { // ========================================================================= - // LocalBinder 定义(与Activity绑定用,Java 7 内部类) + // LocalBinder 定义(与Activity绑定用,Java7内部类) // ========================================================================= public class LocalBinder extends android.os.Binder { private MainService mService; @@ -1015,3 +1038,4 @@ public class MainService extends Service { } +