优化运动状态检测模块,运动状态检测阈值标准未测定。

This commit is contained in:
ZhanGSKen
2025-11-05 16:50:05 +08:00
parent 566e84f53f
commit bf52f86b3d
3 changed files with 368 additions and 245 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Tue Nov 04 12:54:59 GMT 2025
#Wed Nov 05 08:47:36 GMT 2025
stageCount=18
libraryProject=
baseVersion=15.0
publishVersion=15.0.17
buildCount=20
buildCount=29
baseBetaVersion=15.0.18

View File

@@ -3,13 +3,12 @@ package cc.winboll.studio.positions.services;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2024/07/19 14:30:57
* @Describe 应用主要服务组件类适配运动状态GPS控制
* @Describe 应用主要服务组件类适配运动状态GPS控制+静止10秒切换
*/
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;
@@ -25,7 +24,6 @@ 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;
@@ -38,83 +36,125 @@ import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import cc.winboll.studio.positions.utils.LocalMotionDetector;
public class MainService extends Service {
public class MainService extends Service implements LocalMotionDetector.MotionStatusCallback {
public static final String TAG = "MainService";
public static final String EXTRA_IS_SETTING_TO_ENABLE = "EXTRA_IS_SETTING_TO_ENABLE";
// ---------------------- 定时器相关变量 ----------------------
// 静止时GPS定时任务变量Java 7 显式声明)
private ScheduledExecutorService gpsStaticTimer; // 静止时GPS定时获取线程池
private volatile boolean isGpsListening = false; // GPS是否处于持续监听状态
private static final long GPS_STATIC_DURATION = 3; // 静止时GPS单次获取超时时间
// ---------------------- 核心LocalMotionDetector 实例(唯一运动状态检测工具) ----------------------
private LocalMotionDetector mMotionDetector; // 本地运动状态检测器
private static final long GPS_STATIC_INTERVAL = 30; // 静止时GPS间隔30秒
// GPS监听接口Java 7 标准接口定义)
// ---------------------- 定时器相关变量 ----------------------
private ScheduledExecutorService gpsStaticTimer; // 静止时GPS定时任务
private volatile boolean isGpsListening = false; // GPS是否持续监听
private static final long GPS_STATIC_DURATION = 3; // 单次GPS获取超时
// ---------------------- 静止延迟切换配置(核心功能) ----------------------
private static final long STATIC_DELAY_MS = 10 * 1000; // 静止10秒后切换
private Handler staticDelayHandler; // 延迟执行切换逻辑的Handler
private volatile boolean isDelaySwitching = false; // 标记是否正在等待延迟切换
// GPS监听接口
public interface GpsUpdateListener {
void onGpsPositionUpdated(PositionModel currentGpsPos);
void onGpsStatusChanged(String status);
}
// 任务更新监听接口Java 7 风格)
// 任务更新监听接口
public interface TaskUpdateListener {
void onTaskUpdated();
}
// 监听管理(弱引用+线程安全集合适配Java 7
// 监听管理
private final Set<WeakReference<GpsUpdateListener>> mGpsListeners = new HashSet<WeakReference<GpsUpdateListener>>();
private final Set<WeakReference<TaskUpdateListener>> mTaskListeners = new HashSet<WeakReference<TaskUpdateListener>>();
private final Object mListenerLock = new Object(); // 监听操作锁
private final Object mListenerLock = new Object();
// 原有核心变量Java 7 显式初始化)
private LocalBinder mLocalBinder; // 持有 LocalBinder 实例
// 原有核心变量
private LocalBinder mLocalBinder;
private LocationManager mLocationManager;
private LocationListener mGpsLocationListener;
private static final long GPS_UPDATE_INTERVAL = 2000; // GPS更新间隔2秒
private static final float GPS_UPDATE_DISTANCE = 1; // GPS更新距离阈值1米
private boolean isGpsEnabled = false; // GPS是否启用标记
private boolean isGpsPermissionGranted = false; // 定位权限是否授予标记
private static final long GPS_UPDATE_INTERVAL = 2000; // 实时GPS更新间隔2秒
private static final float GPS_UPDATE_DISTANCE = 1; // 实时GPS更新距离1米
private boolean isGpsEnabled = false;
private boolean isGpsPermissionGranted = false;
// 数据存储集合Java 7 基础集合)
private final ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>(); // 位置数据列表
private final ArrayList<PositionTaskModel> mAllTasks = new ArrayList<PositionTaskModel>();// 任务数据列表
private static PositionModel _mCurrentGpsPosition; // 当前GPS定位数据
// 数据存储集合
private final ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>();
private final ArrayList<PositionTaskModel> mAllTasks = new ArrayList<PositionTaskModel>();
private static PositionModel _mCurrentGpsPosition;
// 服务相关变量Java 7 显式声明)
// 服务相关变量
MyServiceConnection mMyServiceConnection;
volatile static boolean _mIsServiceRunning; // 服务运行状态volatile保证可见性
volatile static boolean _mIsServiceRunning;
AppConfigsUtil mAppConfigsUtil;
private ScheduledExecutorService distanceExecutor = Executors.newSingleThreadScheduledExecutor(); // 距离计算线程池
private final Set<String> mVisiblePositionIds = new HashSet<String>(); // 可见位置ID集合
private ScheduledExecutorService distanceExecutor = Executors.newSingleThreadScheduledExecutor();
private final Set<String> mVisiblePositionIds = new HashSet<String>();
// 单例+应用上下文Java 7 静态变量)
// 单例+应用上下文
private static volatile MainService sInstance;
private static Context sAppContext;
// 核心运动状态Receiver动态注册/注销Java 7 显式声明)
private MotionStatusReceiver mMotionStatusReceiver;
private IntentFilter mMotionStatusFilter;
// =========================================================================
// 核心运动状态回调仅通过LocalMotionDetector触发低运动归类为静止
// =========================================================================
@Override
public void onMotionStatusChanged(boolean isWalking, String statusDesc) {
LogUtils.d(TAG, "运动状态回调:" + statusDesc + "isWalking=" + isWalking + "");
updateNotificationGpsStatus("当前状态:" + statusDesc);
// 仅行走状态切实时GPS非行走静止+低运动)统一按静止处理
if (isWalking) {
// 行走状态立即切回实时GPS取消未执行的延迟任务
if (staticDelayHandler != null) {
staticDelayHandler.removeCallbacksAndMessages(null); // 清空延迟任务
isDelaySwitching = false; // 重置标记
}
stopGpsStaticTimer(); // 停止定时GPS
startGpsLocation(); // 启动实时GPS
LogUtils.d(TAG, "行走状态已切换为实时GPS2秒/1米");
} else {
// 非行走状态延迟10秒切换为定时GPS
if (isGpsListening && !isDelaySwitching) { // 仅实时GPS运行且无延迟任务时触发
isDelaySwitching = true;
staticDelayHandler.postDelayed(new Runnable() {
@Override
public void run() {
stopGpsLocation(); // 停止实时GPS
startGpsStaticTimer(GPS_STATIC_INTERVAL); // 启动30秒定时GPS
LogUtils.d(TAG, "静止/低运动10秒已切换为30秒定时GPS");
isDelaySwitching = false; // 重置标记
}
}, STATIC_DELAY_MS);
LogUtils.d(TAG, "检测到静止/低运动将在10秒后切换为定时GPS若持续非行走");
}
LogUtils.d(TAG, "静止/低运动状态等待延迟切换GPS");
}
}
// =========================================================================
// 静止GPS定时任务方法Java 7 语法
// 静止GPS定时任务方法适配Java7
// =========================================================================
// 启动静止时GPS定时获取
public void startGpsStaticTimer(long interval) {
// 先销毁旧定时器(避免重复创建)
// 启动静止时GPS定时获取(间隔:秒)
public void startGpsStaticTimer(long intervalSeconds) {
stopGpsStaticTimer();
// 创建单线程定时器
gpsStaticTimer = Executors.newSingleThreadScheduledExecutor();
gpsStaticTimer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
LogUtils.d(TAG, "静止时GPS定时任务触发开始单次GPS获取");
startSingleGpsRetrieve(); // 单次GPS获取
startSingleGpsRetrieve();
}
}, 0, interval, TimeUnit.MINUTES); // 立即执行第一次,之后按间隔执行
}, 0, intervalSeconds, TimeUnit.SECONDS);
LogUtils.d(TAG, "静止时GPS定时任务已启动间隔" + interval + "分钟");
LogUtils.d(TAG, "静止时GPS定时任务已启动间隔" + intervalSeconds + "");
}
// 停止静止时GPS定时任务
@@ -135,7 +175,7 @@ public class MainService extends Service {
}
}
// 单次GPS获取获取后关闭监听Java 7 匿名内部类
// 单次GPS获取获取后关闭监听
private void startSingleGpsRetrieve() {
if (!checkGpsReady()) {
LogUtils.w(TAG, "单次GPS获取GPS未就绪跳过");
@@ -143,13 +183,11 @@ public class MainService extends Service {
}
try {
// 注册临时GPS监听仅获取一次位置
mLocationManager.requestSingleUpdate(
LocationManager.GPS_PROVIDER,
new LocationListener() {
@Override
public void onLocationChanged(Location location) {
// 获取到位置:同步数据+关闭监听
if (location != null) {
PositionModel gpsPos = new PositionModel();
gpsPos.setLatitude(location.getLatitude());
@@ -159,7 +197,6 @@ public class MainService extends Service {
syncCurrentGpsPosition(gpsPos);
LogUtils.d(TAG, "单次GPS获取成功纬度=" + location.getLatitude());
}
// 移除监听(避免内存泄漏)
mLocationManager.removeUpdates(this);
}
@@ -171,24 +208,23 @@ public class MainService extends Service {
@Override
public void onProviderDisabled(String provider) {
mLocationManager.removeUpdates(this); // 禁用时移除监听
mLocationManager.removeUpdates(this);
}
},
Looper.getMainLooper()
);
// 超时处理:指定时间内未获取则强制关闭
// 超时处理
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
// 移除所有临时监听
mLocationManager.removeUpdates(new LocationListener() {
@Override public void onLocationChanged(Location location) {}
@Override public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override public void onProviderEnabled(String provider) {}
@Override public void onProviderDisabled(String provider) {}
});
LogUtils.d(TAG, "单次GPS获取超时" + GPS_STATIC_DURATION + "秒),已强制关闭监听");
LogUtils.d(TAG, "单次GPS获取超时" + GPS_STATIC_DURATION + "秒)");
}
}, GPS_STATIC_DURATION * 1000);
@@ -201,7 +237,7 @@ public class MainService extends Service {
// =========================================================================
// 任务操作核心接口Java 7 实现)
// 任务操作核心接口
// =========================================================================
public void addTask(PositionTaskModel newTask) {
if (newTask == null || TextUtils.isEmpty(newTask.getPositionId())) {
@@ -209,7 +245,6 @@ public class MainService extends Service {
return;
}
// 任务去重Java 7 迭代器遍历)
boolean isDuplicate = false;
Iterator<PositionTaskModel> taskIter = mAllTasks.iterator();
while (taskIter.hasNext()) {
@@ -236,7 +271,6 @@ public class MainService extends Service {
return posTasks;
}
// 筛选任务Java 7 迭代器遍历)
Iterator<PositionTaskModel> taskIter = mAllTasks.iterator();
while (taskIter.hasNext()) {
PositionTaskModel task = taskIter.next();
@@ -280,7 +314,6 @@ public class MainService extends Service {
return;
}
// 迭代器删除Java 7 安全方式)
Iterator<PositionTaskModel> taskIter = mAllTasks.iterator();
while (taskIter.hasNext()) {
PositionTaskModel task = taskIter.next();
@@ -326,7 +359,6 @@ public class MainService extends Service {
while (iter.hasNext()) {
final WeakReference<TaskUpdateListener> ref = iter.next();
if (ref.get() != null) {
// 主线程判断+切换Java 7 匿名Runnable
if (Looper.myLooper() == Looper.getMainLooper()) {
ref.get().onTaskUpdated();
} else {
@@ -338,7 +370,7 @@ public class MainService extends Service {
});
}
} else {
iter.remove(); // 清理已回收弱引用
iter.remove();
}
}
}
@@ -346,7 +378,7 @@ public class MainService extends Service {
// =========================================================================
// 服务基础方法(核心调整:动态注册/注销MotionStatusReceiver
// 服务基础方法(初始化LocalMotionDetector删除Receiver相关逻辑
// =========================================================================
public static synchronized MainService getInstance(Context context) {
if (sInstance == null) {
@@ -364,7 +396,7 @@ public class MainService extends Service {
@Override
public IBinder onBind(Intent intent) {
return mLocalBinder; // 返回LocalBinder暴露服务
return mLocalBinder;
}
@Override
@@ -374,31 +406,29 @@ public class MainService extends Service {
sInstance = this;
sAppContext = getApplicationContext();
// 初始化LocalBinder
mLocalBinder = new LocalBinder(this);
_mIsServiceRunning = false;
mAppConfigsUtil = AppConfigsUtil.getInstance(this);
// 初始化服务连接
if (mMyServiceConnection == null) {
mMyServiceConnection = new MyServiceConnection();
}
// 初始化GPS监听仅初始化不启动
//initGpsLocationListener();
// 初始化LocalMotionDetector+延迟切换HandlerJava7兼容
mMotionDetector = LocalMotionDetector.getInstance();
staticDelayHandler = new Handler(Looper.getMainLooper());
if (mAppConfigsUtil.isEnableMainService(true)) {
run(); // 启动服务核心逻辑
run();
}
}
// 服务核心运行方法(调整:启动服务时仅注册Receiver不启动GPS
// 服务核心运行方法(删除Receiver注册逻辑
public void run() {
if (mAppConfigsUtil.isEnableMainService(true)) {
if (!_mIsServiceRunning) {
_mIsServiceRunning = true;
wakeupAndBindAssistant(); // 唤醒并绑定辅助服务
wakeupAndBindAssistant();
// 启动前台服务
String initialStatus = "[ Positions ] is in Service.";
@@ -406,23 +436,15 @@ public class MainService extends Service {
startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID,
NotificationUtil.createForegroundServiceNotification(this, initialStatus));
// 初始化LocationManager仅初始化不启动GPS
// 初始化LocationManager
mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
// 加载本地数据
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");
// 核心启动LocalMotionDetector监测唯一运动状态来源
mMotionDetector.startDetection(this, this);
// 提示与日志
ToastUtils.show(initialStatus);
@@ -431,45 +453,6 @@ public class MainService extends Service {
}
}
// 初始化运动状态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;
}
@@ -479,37 +462,44 @@ public class MainService extends Service {
super.onDestroy();
sInstance = null;
// 核心清理1.注销MotionStatusReceiver 2.关闭GPS 3.停止定时任务
unregisterMotionStatusReceiver(); // 注销Receiver避免内存泄漏
stopGpsLocation(); // 强制关闭GPS监听
stopGpsStaticTimer(); // 停止静止时GPS定时任务
// 核心停止LocalMotionDetector避免传感器内存泄漏
if (mMotionDetector != null) {
mMotionDetector.stopDetection();
LogUtils.d(TAG, "LocalMotionDetector 已停止检测");
}
// 其他资源清理
// 清理延迟Handler任务避免内存泄漏
if (staticDelayHandler != null) {
staticDelayHandler.removeCallbacksAndMessages(null);
staticDelayHandler = null;
}
// 原有清理逻辑已删除Receiver注销代码
stopGpsLocation();
stopGpsStaticTimer();
clearAllData();
stopForeground(true);
// 清理所有监听者
synchronized (mListenerLock) {
mGpsListeners.clear();
mTaskListeners.clear();
}
// 销毁线程池
if (distanceExecutor != null && !distanceExecutor.isShutdown()) {
distanceExecutor.shutdown();
}
// 重置状态变量
_mIsServiceRunning = false;
isGpsEnabled = false;
isGpsListening = false;
isDelaySwitching = false;
mLocationManager = null;
LogUtils.d(TAG, "MainService 销毁完成,所有资源已清理");
}
// =========================================================================
// 位置操作方法Java 7 语法)
// 位置操作方法
// =========================================================================
public ArrayList<PositionModel> getPositionList() {
return mPositionList;
@@ -519,7 +509,6 @@ public class MainService extends Service {
return _mCurrentGpsPosition;
}
// 对外提供判断GPS是否处于持续监听状态给MotionStatusReceiver调用
public boolean isGpsListening() {
return isGpsListening;
}
@@ -529,7 +518,6 @@ public class MainService extends Service {
LogUtils.w(TAG, "removePosition参数无效");
return;
}
// 迭代器遍历删除
Iterator<PositionModel> iter = mPositionList.iterator();
while (iter.hasNext()) {
PositionModel pos = iter.next();
@@ -546,7 +534,6 @@ public class MainService extends Service {
LogUtils.w(TAG, "updatePosition参数无效");
return;
}
// 基础for循环查找并更新
for (int i = 0; i < mPositionList.size(); i++) {
PositionModel oldPos = mPositionList.get(i);
if (updatedPos.getPositionId().equals(oldPos.getPositionId())) {
@@ -573,7 +560,6 @@ public class MainService extends Service {
LogUtils.w(TAG, "addPosition位置为空");
return;
}
// 位置去重增强for循环
boolean isDuplicate = false;
for (PositionModel pos : mPositionList) {
if (newPos.getPositionId().equals(pos.getPositionId())) {
@@ -613,7 +599,6 @@ public class MainService extends Service {
LogUtils.d(TAG, "syncCurrentGpsPosition成功纬度=" + position.getLatitude() + ",经度=" + position.getLongitude() + "");
notifyAllGpsListeners(position);
// 服务运行中同步通知栏状态
if (_mIsServiceRunning) {
syncGpsStatusToNotification();
}
@@ -623,14 +608,12 @@ public class MainService extends Service {
if (!_mIsServiceRunning || _mCurrentGpsPosition == null) {
return;
}
// 格式化通知内容
final String gpsStatus = String.format(
"GPS位置北纬%.4f° 东经%.4f° | 可见位置:%d个",
_mCurrentGpsPosition.getLatitude(),
_mCurrentGpsPosition.getLongitude(),
mVisiblePositionIds.size()
);
// 主线程切换
if (Looper.myLooper() == Looper.getMainLooper()) {
NotificationUtil.updateForegroundServiceStatus(this, gpsStatus);
} else {
@@ -645,7 +628,7 @@ public class MainService extends Service {
// =========================================================================
// 服务生命周期+辅助服务相关Java 7 语法)
// 服务生命周期+辅助服务相关
// =========================================================================
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
@@ -653,24 +636,18 @@ public class MainService extends Service {
if (intent != null) {
isSettingToEnable = intent.getBooleanExtra(EXTRA_IS_SETTING_TO_ENABLE, false);
if (isSettingToEnable) {
run(); // 重启服务核心逻辑重新注册Receiver
run();
}
}
// 根据是否自启动返回对应启动模式
return isSettingToEnable ? Service.START_STICKY : super.onStartCommand(intent, flags, startId);
}
// 服务连接内部类
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 空实现(如需绑定辅助服务可补充逻辑)
}
public void onServiceConnected(ComponentName name, IBinder service) {}
@Override
public void onServiceDisconnected(ComponentName name) {
// 辅助服务断开时重新绑定
if (mAppConfigsUtil.isEnableMainService(true)) {
wakeupAndBindAssistant();
}
@@ -678,9 +655,7 @@ public class MainService extends Service {
}
void wakeupAndBindAssistant() {
// 检查辅助服务是否存活
if (!ServiceUtil.isServiceAlive(getApplicationContext(), AssistantService.class.getName())) {
// 启动+绑定辅助服务
startService(new Intent(MainService.this, AssistantService.class));
bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
}
@@ -688,28 +663,25 @@ public class MainService extends Service {
// =========================================================================
// GPS相关核心方法Java 7 语法仅保留Receiver调用的启动/停止逻辑)
// GPS相关核心方法
// =========================================================================
public MainService() {
distanceExecutor = Executors.newSingleThreadScheduledExecutor();
initGpsLocationListener();
}
// 初始化GPS监听仅创建Listener不注册
private void initGpsLocationListener() {
LogUtils.d(TAG, "initGpsLocationListener");
mGpsLocationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (location != null) {
// 封装GPS位置
PositionModel gpsPos = new PositionModel();
gpsPos.setLatitude(location.getLatitude());
gpsPos.setLongitude(location.getLongitude());
gpsPos.setPositionId("CURRENT_GPS_POS");
gpsPos.setMemo("实时GPS位置");
// 同步位置+校验任务
syncCurrentGpsPosition(gpsPos);
DistanceCalculatorUtil.getInstance(MainService.this).checkAllTaskTriggerCondition(gpsPos);
LogUtils.d(TAG, "GPS位置更新纬度=" + location.getLatitude() + ",经度=" + location.getLongitude());
@@ -720,7 +692,6 @@ public class MainService extends Service {
public void onStatusChanged(String provider, int status, Bundle extras) {
if (provider.equals(LocationManager.GPS_PROVIDER)) {
String statusDesc = "";
// Java 7 基础switch
switch (status) {
case LocationProvider.AVAILABLE:
statusDesc = "GPS状态已就绪可用";
@@ -745,8 +716,7 @@ public class MainService extends Service {
String statusDesc = "GPS已开启用户手动打开";
LogUtils.d(TAG, statusDesc);
notifyAllGpsStatusListeners(statusDesc);
updateNotificationGpsStatus("GPS已开启等待Receiver控制启动...");
// 不主动启动GPS由Receiver根据运动状态控制
updateNotificationGpsStatus("GPS已开启等待运动状态触发...");
}
}
@@ -766,20 +736,15 @@ public class MainService extends Service {
};
}
// GPS就绪检查给Receiver调用的GPS操作做前置判断
private boolean checkGpsReady() {
// 检查定位权限
isGpsPermissionGranted = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
// 初始化LocationManager
if (mLocationManager == null) {
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
// 检查GPS是否启用
isGpsEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
// 权限未授予处理
if (!isGpsPermissionGranted) {
String tip = "GPS准备失败缺少精确定位权限";
LogUtils.e(TAG, tip);
@@ -788,7 +753,6 @@ public class MainService extends Service {
ToastUtils.show("请授予定位权限否则无法获取GPS位置");
return false;
}
// GPS未启用处理
if (!isGpsEnabled) {
String tip = "GPS准备失败系统GPS未开启";
LogUtils.e(TAG, tip);
@@ -802,14 +766,13 @@ public class MainService extends Service {
return true;
}
// 启动GPS持续监听仅Receiver可调用)
// 启动GPS持续监听运动状态回调调用)
public void startGpsLocation() {
if (!checkGpsReady() || isGpsListening) {
return;
}
try {
// 注册GPS位置更新
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
GPS_UPDATE_INTERVAL,
@@ -818,10 +781,9 @@ public class MainService extends Service {
Looper.getMainLooper()
);
// 标记GPS进入持续监听状态
isGpsListening = true;
// 获取最后已知GPS位置
// 获取最后已知位置
Location lastKnownLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKnownLocation != null) {
PositionModel lastGpsPos = new PositionModel();
@@ -853,9 +815,8 @@ public class MainService extends Service {
}
}
// 停止GPS持续监听仅Receiver可调用)
// 停止GPS持续监听运动状态回调调用)
public void stopGpsLocation() {
// 校验参数:避免空指针+权限未授予时调用
if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) {
try {
mLocationManager.removeUpdates(mGpsLocationListener);
@@ -878,7 +839,6 @@ public class MainService extends Service {
return;
}
// 格式化通知内容
final String triggerContent = String.format(
"任务触发:%s\n位置%s\n当前距离%.1f米(条件:%s%d米",
task.getTaskDescription(),
@@ -888,10 +848,8 @@ public class MainService extends Service {
task.getDiscussDistance()
);
// 更新前台通知
updateNotificationGpsStatus(triggerContent);
// 显示Toast主线程安全
if (Looper.myLooper() == Looper.getMainLooper()) {
ToastUtils.show(triggerContent);
NotificationUtil.show(MainService.this, task.getTaskId(), task.getPositionId(), task.getTaskDescription());
@@ -910,7 +868,6 @@ public class MainService extends Service {
// 更新前台通知的GPS状态
void updateNotificationGpsStatus(final String statusText) {
if (_mIsServiceRunning) {
// 主线程判断+切换Java7匿名内部类
if (Looper.myLooper() == Looper.getMainLooper()) {
NotificationUtil.updateForegroundServiceStatus(this, statusText);
} else {
@@ -926,7 +883,7 @@ public class MainService extends Service {
// =========================================================================
// GPS监听通知相关方法Java7语法给外部监听者回调
// GPS监听通知相关方法
// =========================================================================
public void notifyAllGpsListeners(PositionModel currentGpsPos) {
if (currentGpsPos == null || mGpsListeners.isEmpty()) {
@@ -940,7 +897,7 @@ public class MainService extends Service {
if (listener != null) {
notifySingleListener(listener, currentGpsPos);
} else {
iter.remove(); // 清理已回收监听者
iter.remove();
}
}
}
@@ -969,7 +926,6 @@ public class MainService extends Service {
WeakReference<GpsUpdateListener> ref = iter.next();
final GpsUpdateListener listener = ref.get();
if (listener != null) {
// 主线程切换避免UI异常Java7匿名Runnable
if (Looper.myLooper() == Looper.getMainLooper()) {
listener.onGpsStatusChanged(status);
} else {
@@ -981,7 +937,7 @@ public class MainService extends Service {
});
}
} else {
iter.remove(); // 清理无效弱引用
iter.remove();
}
}
}
@@ -995,7 +951,6 @@ public class MainService extends Service {
synchronized (mListenerLock) {
mGpsListeners.add(new WeakReference<GpsUpdateListener>(listener));
LogUtils.d(TAG, "GPS监听注册成功当前数量" + mGpsListeners.size());
// 注册后推送当前GPS位置避免监听者遗漏初始数据
if (_mCurrentGpsPosition != null) {
notifySingleListener(listener, _mCurrentGpsPosition);
}
@@ -1021,9 +976,9 @@ public class MainService extends Service {
}
// =========================================================================
// LocalBinder 定义(与Activity绑定用Java7内部类
// =========================================================================
// =========================================================================
// LocalBinder 定义(无修改
// =========================================================================
public class LocalBinder extends android.os.Binder {
private MainService mService;
@@ -1032,7 +987,7 @@ public class MainService extends Service {
}
public MainService getService() {
return mService; // 暴露MainService实例给绑定的Activity
return mService;
}
}
}

View File

@@ -0,0 +1,168 @@
package cc.winboll.studio.positions.utils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/11/05 15:49
* @Describe LocalMotionDetector
*/
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import cc.winboll.studio.libappbase.LogUtils;
/**
* 本机运动状态监测工具(无联网,纯传感器)
*/
public class LocalMotionDetector implements SensorEventListener {
public static final String TAG = "LocalMotionDetector";
// 配置参数(重点修改:调高运动阈值,适配坐立持机场景)
private static final float MOTION_THRESHOLD = 1.8f; // 从0.5f调高到1.8f(过滤坐立轻微晃动)
private static final long STATUS_CHECK_INTERVAL = 3000; // 3秒判断一次状态
private static final int STEP_CHANGE_THRESHOLD = 2; // 3秒≥2步判定行走
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Sensor mStepCounter;
private Handler mMainHandler;
private MotionStatusCallback mCallback;
private boolean mIsDetecting = false;
private float mLastAccelMagnitude = 0f;
private int mLastStepCount = 0;
private int mCurrentStepCount = 0;
private boolean mIsWalking = false;
// 单例模式
private static LocalMotionDetector sInstance;
public static LocalMotionDetector getInstance() {
if (sInstance == null) {
synchronized (LocalMotionDetector.class) {
if (sInstance == null) {
sInstance = new LocalMotionDetector();
}
}
}
return sInstance;
}
private LocalMotionDetector() {
mMainHandler = new Handler(Looper.getMainLooper());
}
/**
* 开始监测运动状态
*/
public void startDetection(Context context, MotionStatusCallback callback) {
if (mIsDetecting) return;
mCallback = callback;
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
// 初始化传感器
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mStepCounter = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
// 注册传感器监听
if (mAccelerometer != null) {
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL, mMainHandler);
}
if (mStepCounter != null) {
mSensorManager.registerListener(this, mStepCounter, SensorManager.SENSOR_DELAY_NORMAL, mMainHandler);
LogUtils.d(TAG, "计步传感器已启动");
} else {
LogUtils.d(TAG, "设备不支持计步传感器,仅用加速度判断");
}
// 启动定时状态检测
mMainHandler.postDelayed(mStatusCheckRunnable, STATUS_CHECK_INTERVAL);
mIsDetecting = true;
LogUtils.d(TAG, "运动状态监测已启动");
}
/**
* 停止监测
*/
public void stopDetection() {
if (!mIsDetecting) return;
if (mSensorManager != null) {
mSensorManager.unregisterListener(this);
}
mMainHandler.removeCallbacksAndMessages(null);
mIsDetecting = false;
mIsWalking = false;
mCallback = null;
LogUtils.d(TAG, "运动状态监测已停止");
}
@Override
public void onSensorChanged(SensorEvent event) {
if (!mIsDetecting) return;
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
// 计算加速度幅度(保留原逻辑,阈值已调高)
float accelX = Math.abs(event.values[0]);
float accelY = Math.abs(event.values[1]);
float accelZ = Math.abs(event.values[2]);
mLastAccelMagnitude = accelX + accelY + accelZ;
break;
case Sensor.TYPE_STEP_COUNTER:
// 累计步数
mCurrentStepCount = (int) event.values[0];
break;
}
}
/**
* 定时判断运动状态优化逻辑计步为0时即使有轻微加速度也判定为静止
*/
private final Runnable mStatusCheckRunnable = new Runnable() {
@Override
public void run() {
if (!mIsDetecting || mCallback == null) return;
//LogUtils.d(TAG, "mStatusCheckRunnable run");
boolean newIsWalking = false;
// 结合计步器+加速度判断(优化:优先计步,无步数时严格按高阈值判断)
if (mStepCounter != null) {
int stepChange = mCurrentStepCount - mLastStepCount;
// 只有“步数达标” 或 “无步数但加速度远超坐立幅度”,才判定为行走
newIsWalking = (stepChange >= STEP_CHANGE_THRESHOLD)
&& (mLastAccelMagnitude >= MOTION_THRESHOLD); // 增加步数+加速度双重校验
mLastStepCount = mCurrentStepCount;
} else {
// 无计步器时,仅用高阈值判断
newIsWalking = mLastAccelMagnitude >= MOTION_THRESHOLD;
}
// 状态变化时回调
if (newIsWalking != mIsWalking) {
mIsWalking = newIsWalking;
String statusDesc = mIsWalking ? "行走状态" : "静止/低运动状态";
LogUtils.d(TAG, "运动状态变化:" + statusDesc + " | 加速度幅度:" + mLastAccelMagnitude); // 增加日志便于调试
mCallback.onMotionStatusChanged(mIsWalking, statusDesc);
}
LogUtils.d(TAG, String.format("运动状态 newIsWalking %s", newIsWalking));
// 循环检测
mMainHandler.postDelayed(this, STATUS_CHECK_INTERVAL);
}
};
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
/**
* 运动状态回调接口
*/
public interface MotionStatusCallback {
void onMotionStatusChanged(boolean isWalking, String statusDesc);
}
}