基本完成传感器陀螺仪启动,与接收器接收功能。

This commit is contained in:
ZhanGSKen
2025-11-04 20:56:31 +08:00
parent 2d3cee1121
commit 566e84f53f
4 changed files with 472 additions and 205 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #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 stageCount=18
libraryProject= libraryProject=
baseVersion=15.0 baseVersion=15.0
publishVersion=15.0.17 publishVersion=15.0.17
buildCount=0 buildCount=20
baseBetaVersion=15.0.18 baseBetaVersion=15.0.18

View File

@@ -3,24 +3,24 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.positions"> package="cc.winboll.studio.positions">
<!-- 1. 声明GPS权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 前台服务权限(可选,提升后台定位稳定性,避免服务被回收) -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- 只能在前台获取精确的位置信息 --> <!-- 只能在前台获取精确的位置信息 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 只有在前台运行时才能获取大致位置信息 --> <!-- 只有在前台运行时才能获取大致位置信息 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 在后台使用位置信息 --> <!-- 在后台使用位置信息 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<!-- 运行前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- 运行“location”类型的前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature <uses-feature
android:name="android.hardware.location.gps" android:name="android.hardware.location.gps"
android:required="false"/> android:required="false"/>
@@ -59,22 +59,28 @@
android:name="com.google.android.gms.version" android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/> android:value="@integer/google_play_services_version"/>
<service android:name=".services.MainService"/> <service
android:name=".services.MainService"
android:exported="false"/>
<service android:name=".services.AssistantService"/> <service
android:name=".services.AssistantService"
android:exported="false"/>
<service android:name=".services.DistanceRefreshService"/> <service
android:name=".services.DistanceRefreshService"
android:exported="false"/>
<receiver android:name="cc.winboll.studio.positions.receivers.MotionStatusReceiver">
<intent-filter>
<action android:name="cc.winboll.studio.positions.receivers.MotionStatusReceiver"/>
</intent-filter>
</receiver>
<!-- 2. 注册运动状态Receiver -->
<receiver
android:name="cc.winboll.studio.positions.receivers.MotionStatusReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="cc.winboll.studio.positions.ACTION_MOTION_STATUS" />
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>

View File

@@ -9,116 +9,353 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; 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.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils; import android.text.TextUtils;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.positions.services.MainService; import cc.winboll.studio.positions.services.MainService;
import cc.winboll.studio.positions.utils.ServiceUtil; import cc.winboll.studio.positions.utils.ServiceUtil;
/** /**
* 运动状态监听Receiver * 运动状态监听Receiver
* 功能:接收运动状态广播控制GPS权限申请与GPS监听开关 * 功能:1.持续监听传感器(不关闭) 2.每5秒计算运动状态 3.按状态切换GPS模式实时/30秒定时
*/ */
public class MotionStatusReceiver extends BroadcastReceiver { public class MotionStatusReceiver extends BroadcastReceiver implements SensorEventListener {
public static final String TAG = "MotionStatusReceiver"; public static final String TAG = "MotionStatusReceiver";
// 运动状态广播Action(需与运动状态发送方保持一致,如传感器服务) // 广播Action
public static final String ACTION_MOTION_STATUS = "cc.winboll.studio.positions.ACTION_MOTION_STATUS"; public static final String ACTION_MOTION_STATUS_RECEIVER = "cc.winboll.studio.positions.receivers.MotionStatusReceiver";
// 运动状态Extra键0=静止/低运动1=行走/高运动 public static final String EXTRA_SENSORS_ENABLE = "EXTRA_SENSORS_ENABLE";
public static final String EXTRA_MOTION_STATUS = "EXTRA_MOTION_STATUS"; // 传感器启动状态标志位
// 静止时GPS定时获取间隔单位分钟可配置 boolean mIsSensorsEnable = false;
public static final long GPS_STATIC_INTERVAL = 1; // 运动状态常量
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 @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (context == null || intent == null || !TextUtils.equals(intent.getAction(), ACTION_MOTION_STATUS)) {
LogUtils.w(TAG, "无效广播Action不匹配或上下文为空");
return;
}
// 1. 获取运动状态0=静止/低运动1=行走/高运动) LogUtils.d(TAG, "===== 接收器启动onReceive() 开始执行 =====");
int motionStatus = intent.getIntExtra(EXTRA_MOTION_STATUS, 0); this.mBroadcastContext = context;
LogUtils.d(TAG, "接收运动状态:" + (motionStatus == 1 ? "行走中" : "静止/低运动")); mMainHandler = new Handler(Looper.getMainLooper());
// 2. 绑定并获取MainService实例确保服务已启动 if (TextUtils.equals(intent.getAction(), ACTION_MOTION_STATUS_RECEIVER)) {
MainService mainService = getMainService(context); boolean isSettingEnable = intent.getBooleanExtra(EXTRA_SENSORS_ENABLE, false);
if (mainService == null) { if (mIsSensorsEnable == false && isSettingEnable == true) {
LogUtils.e(TAG, "MainService未启动无法控制GPS状态"); mIsSensorsEnable = true;
return; // 1. 初始化传感器(必执行)
} initSensors();
// 3. 根据运动状态处理GPS逻辑 if (mAccelerometer == null || mGyroscope == null) {
if (motionStatus == 1) { LogUtils.e(TAG, "设备缺少加速度/陀螺仪,无法持续监听");
// 3.1 行走中申请GPS权限若未授予+ 开启持续GPS监听 cleanResources(false); // 传感器不可用才清理
handleWalkingStatus(mainService, context); return;
} else { }
// 3.2 静止/低运动关闭持续GPS监听 + 启动定时GPS获取
handleStaticStatus(mainService);
}
}
/** // 2. 校验参数
* 处理行走状态申请GPS权限+开启持续GPS监听 if (context == null || intent == null) {
*/ LogUtils.d(TAG, "onReceive():无效参数,终止处理");
private void handleWalkingStatus(MainService mainService, Context context) { cleanResources(false);
// 检查GPS权限Android 6.0+动态权限) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && }
context.checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) LogUtils.d(TAG, "onReceive()接收到广播Action=" + intent.getAction());
!= 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;
}
// 权限已授予开启持续GPS监听调用MainService原有方法 // 3. 启动持续传感器监听(核心:不关闭,重复调用无影响
if (!mainService.isGpsListening()) { // 需在MainService中新增isGpsListening()方法 startSensorListening();
mainService.startGpsLocation();
LogUtils.d(TAG, "行走中已开启持续GPS监听");
}
// 停止静止时的GPS定时任务避免重复获取 // 4. 启动5秒定时计算运动状态核心持续触发状态判断
mainService.stopGpsStaticTimer(); startStatusCalcTimer();
}
/**
* 处理静止状态关闭持续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();
} }
} }
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); // 强制停止传感器
}
} }

View File

@@ -9,6 +9,7 @@ import android.app.Service;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.location.Location; import android.location.Location;
@@ -24,6 +25,7 @@ import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import cc.winboll.studio.positions.models.PositionModel; import cc.winboll.studio.positions.models.PositionModel;
import cc.winboll.studio.positions.models.PositionTaskModel; 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.AppConfigsUtil;
import cc.winboll.studio.positions.utils.DistanceCalculatorUtil; import cc.winboll.studio.positions.utils.DistanceCalculatorUtil;
import cc.winboll.studio.positions.utils.NotificationUtil; 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"; public static final String EXTRA_IS_SETTING_TO_ENABLE = "EXTRA_IS_SETTING_TO_ENABLE";
// ---------------------- 定时器相关变量 ---------------------- // ---------------------- 定时器相关变量 ----------------------
private ScheduledExecutorService taskCheckTimer; // 任务校验定时器 // 静止时GPS定时任务变量Java 7 显式声明)
private static final long TASK_CHECK_INTERVAL = 1; // 定时间隔1分钟
private static final long TASK_CHECK_INIT_DELAY = 1; // 初始延迟1分钟
// 新增静止时GPS定时任务变量Java 7 显式声明)
private ScheduledExecutorService gpsStaticTimer; // 静止时GPS定时获取线程池 private ScheduledExecutorService gpsStaticTimer; // 静止时GPS定时获取线程池
private volatile boolean isGpsListening = false; // GPS是否处于持续监听状态 private volatile boolean isGpsListening = false; // GPS是否处于持续监听状态
private static final long GPS_STATIC_DURATION = 3; // 静止时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 volatile MainService sInstance;
private static Context sAppContext; private static Context sAppContext;
// 核心运动状态Receiver动态注册/注销Java 7 显式声明)
private MotionStatusReceiver mMotionStatusReceiver;
private IntentFilter mMotionStatusFilter;
// ========================================================================= // =========================================================================
// 定时器初始化方法(任务校验+静止GPS定时 // 静止GPS定时任务方法Java 7 语法
// ========================================================================= // =========================================================================
/*private void initTaskCheckTimer() { // 启动静止时GPS定时获取
// 先销毁旧定时器(避免重复创建)
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
public void startGpsStaticTimer(long interval) { public void startGpsStaticTimer(long interval) {
// 先销毁旧定时器(避免重复创建) // 先销毁旧定时器(避免重复创建)
stopGpsStaticTimer(); stopGpsStaticTimer();
@@ -150,7 +117,7 @@ public class MainService extends Service {
LogUtils.d(TAG, "静止时GPS定时任务已启动间隔" + interval + "分钟)"); LogUtils.d(TAG, "静止时GPS定时任务已启动间隔" + interval + "分钟)");
} }
// 新增:停止静止时GPS定时任务 // 停止静止时GPS定时任务
public void stopGpsStaticTimer() { public void stopGpsStaticTimer() {
if (gpsStaticTimer != null && !gpsStaticTimer.isShutdown()) { if (gpsStaticTimer != null && !gpsStaticTimer.isShutdown()) {
gpsStaticTimer.shutdown(); gpsStaticTimer.shutdown();
@@ -168,7 +135,7 @@ public class MainService extends Service {
} }
} }
// 新增:单次GPS获取获取后关闭监听Java 7 匿名内部类) // 单次GPS获取获取后关闭监听Java 7 匿名内部类)
private void startSingleGpsRetrieve() { private void startSingleGpsRetrieve() {
if (!checkGpsReady()) { if (!checkGpsReady()) {
LogUtils.w(TAG, "单次GPS获取GPS未就绪跳过"); LogUtils.w(TAG, "单次GPS获取GPS未就绪跳过");
@@ -379,7 +346,7 @@ public class MainService extends Service {
// ========================================================================= // =========================================================================
// 原有基础方法(Java 7 语法适配 // 服务基础方法(核心调整:动态注册/注销MotionStatusReceiver
// ========================================================================= // =========================================================================
public static synchronized MainService getInstance(Context context) { public static synchronized MainService getInstance(Context context) {
if (sInstance == null) { if (sInstance == null) {
@@ -418,15 +385,19 @@ public class MainService extends Service {
mMyServiceConnection = new MyServiceConnection(); mMyServiceConnection = new MyServiceConnection();
} }
// 初始化GPS监听仅初始化不启动
//initGpsLocationListener();
if (mAppConfigsUtil.isEnableMainService(true)) { if (mAppConfigsUtil.isEnableMainService(true)) {
run(); // 启动服务核心逻辑 run(); // 启动服务核心逻辑
} }
} }
// 服务核心运行方法调整启动服务时仅注册Receiver不启动GPS
public void run() { public void run() {
if (mAppConfigsUtil.isEnableMainService(true)) { if (mAppConfigsUtil.isEnableMainService(true)) {
if (!_mIsServiceRunning) { if (!_mIsServiceRunning) {
_mIsServiceRunning = true; _mIsServiceRunning = true;
wakeupAndBindAssistant(); // 唤醒并绑定辅助服务 wakeupAndBindAssistant(); // 唤醒并绑定辅助服务
// 启动前台服务 // 启动前台服务
@@ -435,25 +406,70 @@ public class MainService extends Service {
startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID, startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID,
NotificationUtil.createForegroundServiceNotification(this, initialStatus)); NotificationUtil.createForegroundServiceNotification(this, initialStatus));
// 初始化GPS相关 // 初始化LocationManager仅初始化不启动GPS
mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE); mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
initGpsLocationListener();
startGpsLocation();
// 加载本地数据 // 加载本地数据
PositionModel.loadBeanList(MainService.this, mPositionList, PositionModel.class); PositionModel.loadBeanList(MainService.this, mPositionList, PositionModel.class);
PositionTaskModel.loadBeanList(MainService.this, mAllTasks, PositionTaskModel.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); ToastUtils.show(initialStatus);
LogUtils.i(TAG, 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() { public boolean isServiceRunning() {
return _mIsServiceRunning; return _mIsServiceRunning;
} }
@@ -463,8 +479,12 @@ public class MainService extends Service {
super.onDestroy(); super.onDestroy();
sInstance = null; sInstance = null;
// 清理资源 // 核心清理1.注销MotionStatusReceiver 2.关闭GPS 3.停止定时任务
stopGpsLocation(); unregisterMotionStatusReceiver(); // 注销Receiver避免内存泄漏
stopGpsLocation(); // 强制关闭GPS监听
stopGpsStaticTimer(); // 停止静止时GPS定时任务
// 其他资源清理
clearAllData(); clearAllData();
stopForeground(true); stopForeground(true);
@@ -474,9 +494,7 @@ public class MainService extends Service {
mTaskListeners.clear(); mTaskListeners.clear();
} }
// 销毁所有定时器与线程池 // 销毁线程池
//destroyTaskCheckTimer();
stopGpsStaticTimer(); // 新增销毁静止时GPS定时任务
if (distanceExecutor != null && !distanceExecutor.isShutdown()) { if (distanceExecutor != null && !distanceExecutor.isShutdown()) {
distanceExecutor.shutdown(); distanceExecutor.shutdown();
} }
@@ -484,8 +502,9 @@ public class MainService extends Service {
// 重置状态变量 // 重置状态变量
_mIsServiceRunning = false; _mIsServiceRunning = false;
isGpsEnabled = false; isGpsEnabled = false;
isGpsListening = false; // 新增重置GPS监听状态 isGpsListening = false;
mLocationManager = null; mLocationManager = null;
LogUtils.d(TAG, "MainService 销毁完成,所有资源已清理");
} }
@@ -500,7 +519,7 @@ public class MainService extends Service {
return _mCurrentGpsPosition; return _mCurrentGpsPosition;
} }
// 新增判断GPS是否处于持续监听状态给Receiver调用 // 对外提供判断GPS是否处于持续监听状态MotionStatusReceiver调用
public boolean isGpsListening() { public boolean isGpsListening() {
return isGpsListening; return isGpsListening;
} }
@@ -606,10 +625,10 @@ public class MainService extends Service {
} }
// 格式化通知内容 // 格式化通知内容
final String gpsStatus = String.format( final String gpsStatus = String.format(
"GPS位置北纬%.4f° 东经%.4f° | 可见位置:%d个", "GPS位置北纬%.4f° 东经%.4f° | 可见位置:%d个",
_mCurrentGpsPosition.getLatitude(), _mCurrentGpsPosition.getLatitude(),
_mCurrentGpsPosition.getLongitude(), _mCurrentGpsPosition.getLongitude(),
mVisiblePositionIds.size() mVisiblePositionIds.size()
); );
// 主线程切换 // 主线程切换
if (Looper.myLooper() == Looper.getMainLooper()) { if (Looper.myLooper() == Looper.getMainLooper()) {
@@ -634,7 +653,7 @@ public class MainService extends Service {
if (intent != null) { if (intent != null) {
isSettingToEnable = intent.getBooleanExtra(EXTRA_IS_SETTING_TO_ENABLE, false); isSettingToEnable = intent.getBooleanExtra(EXTRA_IS_SETTING_TO_ENABLE, false);
if (isSettingToEnable) { if (isSettingToEnable) {
run(); // 重启服务核心逻辑 run(); // 重启服务核心逻辑重新注册Receiver
} }
} }
@@ -669,13 +688,14 @@ public class MainService extends Service {
// ========================================================================= // =========================================================================
// GPS相关核心方法Java 7 语法,匿名内部类实现 // GPS相关核心方法Java 7 语法,仅保留Receiver调用的启动/停止逻辑
// ========================================================================= // =========================================================================
public MainService() { public MainService() {
distanceExecutor = Executors.newSingleThreadScheduledExecutor(); distanceExecutor = Executors.newSingleThreadScheduledExecutor();
initGpsLocationListener(); initGpsLocationListener();
} }
// 初始化GPS监听仅创建Listener不注册
private void initGpsLocationListener() { private void initGpsLocationListener() {
LogUtils.d(TAG, "initGpsLocationListener"); LogUtils.d(TAG, "initGpsLocationListener");
mGpsLocationListener = new LocationListener() { mGpsLocationListener = new LocationListener() {
@@ -725,8 +745,8 @@ public class MainService extends Service {
String statusDesc = "GPS已开启用户手动打开"; String statusDesc = "GPS已开启用户手动打开";
LogUtils.d(TAG, statusDesc); LogUtils.d(TAG, statusDesc);
notifyAllGpsStatusListeners(statusDesc); notifyAllGpsStatusListeners(statusDesc);
updateNotificationGpsStatus("GPS已开启正在获取位置..."); updateNotificationGpsStatus("GPS已开启等待Receiver控制启动...");
startGpsLocation(); // 不主动启动GPS由Receiver根据运动状态控制
} }
} }
@@ -734,7 +754,7 @@ public class MainService extends Service {
public void onProviderDisabled(String provider) { public void onProviderDisabled(String provider) {
if (provider.equals(LocationManager.GPS_PROVIDER)) { if (provider.equals(LocationManager.GPS_PROVIDER)) {
isGpsEnabled = false; isGpsEnabled = false;
isGpsListening = false; // 新增GPS禁用时重置监听状态 isGpsListening = false;
_mCurrentGpsPosition = null; _mCurrentGpsPosition = null;
String statusDesc = "GPS已关闭用户手动关闭"; String statusDesc = "GPS已关闭用户手动关闭";
LogUtils.w(TAG, statusDesc); LogUtils.w(TAG, statusDesc);
@@ -746,10 +766,11 @@ public class MainService extends Service {
}; };
} }
// GPS就绪检查给Receiver调用的GPS操作做前置判断
private boolean checkGpsReady() { private boolean checkGpsReady() {
// 检查定位权限 // 检查定位权限
isGpsPermissionGranted = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) isGpsPermissionGranted = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED; == PackageManager.PERMISSION_GRANTED;
// 初始化LocationManager // 初始化LocationManager
if (mLocationManager == null) { if (mLocationManager == null) {
@@ -781,22 +802,23 @@ public class MainService extends Service {
return true; return true;
} }
// 启动GPS持续监听仅Receiver可调用
public void startGpsLocation() { public void startGpsLocation() {
if (!checkGpsReady()) { if (!checkGpsReady() || isGpsListening) {
return; return;
} }
try { try {
// 注册GPS位置更新 // 注册GPS位置更新
mLocationManager.requestLocationUpdates( mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LocationManager.GPS_PROVIDER,
GPS_UPDATE_INTERVAL, GPS_UPDATE_INTERVAL,
GPS_UPDATE_DISTANCE, GPS_UPDATE_DISTANCE,
mGpsLocationListener, mGpsLocationListener,
Looper.getMainLooper() Looper.getMainLooper()
); );
// 新增:标记GPS进入持续监听状态 // 标记GPS进入持续监听状态
isGpsListening = true; isGpsListening = true;
// 获取最后已知GPS位置 // 获取最后已知GPS位置
@@ -820,17 +842,18 @@ public class MainService extends Service {
LogUtils.e(TAG, error); LogUtils.e(TAG, error);
notifyAllGpsStatusListeners(error); notifyAllGpsStatusListeners(error);
isGpsPermissionGranted = false; isGpsPermissionGranted = false;
isGpsListening = false; // 新增:异常时重置监听状态 isGpsListening = false;
updateNotificationGpsStatus("定位权限异常无法获取GPS"); updateNotificationGpsStatus("定位权限异常无法获取GPS");
} catch (Exception e) { } catch (Exception e) {
String error = "启动GPS失败" + e.getMessage(); String error = "启动GPS失败" + e.getMessage();
LogUtils.e(TAG, error); LogUtils.e(TAG, error);
notifyAllGpsStatusListeners(error); notifyAllGpsStatusListeners(error);
isGpsListening = false; // 新增:异常时重置监听状态 isGpsListening = false;
updateNotificationGpsStatus("GPS启动失败尝试重试..."); updateNotificationGpsStatus("GPS启动失败尝试重试...");
} }
} }
// 停止GPS持续监听仅Receiver可调用
public void stopGpsLocation() { public void stopGpsLocation() {
// 校验参数:避免空指针+权限未授予时调用 // 校验参数:避免空指针+权限未授予时调用
if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) { if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) {
@@ -839,12 +862,12 @@ public class MainService extends Service {
String tip = "GPS定位已停止移除监听器"; String tip = "GPS定位已停止移除监听器";
LogUtils.d(TAG, tip); LogUtils.d(TAG, tip);
notifyAllGpsStatusListeners(tip); notifyAllGpsStatusListeners(tip);
isGpsListening = false; // 新增:停止监听时重置状态 isGpsListening = false;
} catch (Exception e) { } catch (Exception e) {
String error = "停止GPS失败" + e.getMessage(); String error = "停止GPS失败" + e.getMessage();
LogUtils.e(TAG, error); LogUtils.e(TAG, error);
notifyAllGpsStatusListeners(error); notifyAllGpsStatusListeners(error);
isGpsListening = false; // 新增:异常时重置状态 isGpsListening = false;
} }
} }
} }
@@ -857,12 +880,12 @@ public class MainService extends Service {
// 格式化通知内容 // 格式化通知内容
final String triggerContent = String.format( final String triggerContent = String.format(
"任务触发:%s\n位置%s\n当前距离%.1f米(条件:%s%d米", "任务触发:%s\n位置%s\n当前距离%.1f米(条件:%s%d米",
task.getTaskDescription(), task.getTaskDescription(),
bindPos.getMemo(), bindPos.getMemo(),
currentDistance, currentDistance,
task.isGreaterThan() ? ">" : "<", task.isGreaterThan() ? ">" : "<",
task.getDiscussDistance() task.getDiscussDistance()
); );
// 更新前台通知 // 更新前台通知
@@ -887,7 +910,7 @@ public class MainService extends Service {
// 更新前台通知的GPS状态 // 更新前台通知的GPS状态
void updateNotificationGpsStatus(final String statusText) { void updateNotificationGpsStatus(final String statusText) {
if (_mIsServiceRunning) { if (_mIsServiceRunning) {
// 主线程判断+切换 // 主线程判断+切换Java7匿名内部类
if (Looper.myLooper() == Looper.getMainLooper()) { if (Looper.myLooper() == Looper.getMainLooper()) {
NotificationUtil.updateForegroundServiceStatus(this, statusText); NotificationUtil.updateForegroundServiceStatus(this, statusText);
} else { } else {
@@ -903,7 +926,7 @@ public class MainService extends Service {
// ========================================================================= // =========================================================================
// GPS监听通知相关方法Java 7 语法 // GPS监听通知相关方法Java7语法给外部监听者回调
// ========================================================================= // =========================================================================
public void notifyAllGpsListeners(PositionModel currentGpsPos) { public void notifyAllGpsListeners(PositionModel currentGpsPos) {
if (currentGpsPos == null || mGpsListeners.isEmpty()) { if (currentGpsPos == null || mGpsListeners.isEmpty()) {
@@ -946,7 +969,7 @@ public class MainService extends Service {
WeakReference<GpsUpdateListener> ref = iter.next(); WeakReference<GpsUpdateListener> ref = iter.next();
final GpsUpdateListener listener = ref.get(); final GpsUpdateListener listener = ref.get();
if (listener != null) { if (listener != null) {
// 主线程切换避免UI异常 // 主线程切换避免UI异常Java7匿名Runnable
if (Looper.myLooper() == Looper.getMainLooper()) { if (Looper.myLooper() == Looper.getMainLooper()) {
listener.onGpsStatusChanged(status); listener.onGpsStatusChanged(status);
} else { } else {
@@ -999,7 +1022,7 @@ public class MainService extends Service {
// ========================================================================= // =========================================================================
// LocalBinder 定义与Activity绑定用Java 7 内部类) // LocalBinder 定义与Activity绑定用Java7内部类)
// ========================================================================= // =========================================================================
public class LocalBinder extends android.os.Binder { public class LocalBinder extends android.os.Binder {
private MainService mService; private MainService mService;
@@ -1015,3 +1038,4 @@ public class MainService extends Service {
} }