feat: 实现应用空转状态持久化与MainService动态数据源切换
1. App.java: - 添加SharedPreferences持久化空转状态,App重启后自动恢复 - setAppIdleRunning()中增加MainService服务重启逻辑,同步空转状态 2. MainService.java: - onCreate/onStartCommand: 检测空转状态,自动启动IdleGpsService - 重构GPS监听逻辑,新增mIdleGpsListener实例与中央处理方法 - startGpsLocation/stopGpsLocation: 根据空转状态自动切换系统GPS与IdleGpsService数据源 - 前台通知栏显示 [IDLE RUNNING] 标识及全精度(%.15f)经纬度数据 - 通知内容区分"空转GPS"与真实"GPS位置"前缀 3. IdleGpsService.java: - 添加服务启动时的Toast提示反馈 - 修复MainService中IdleGpsService类型不匹配问题 4. MainActivity.java: - 简化空转切换逻辑,移除冗余的IdleGpsService手动启停代码
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Mon May 04 03:36:37 CST 2026
|
||||
#Mon May 04 09:35:11 CST 2026
|
||||
stageCount=20
|
||||
libraryProject=
|
||||
baseVersion=15.12
|
||||
publishVersion=15.12.19
|
||||
buildCount=23
|
||||
buildCount=29
|
||||
baseBetaVersion=15.12.20
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Typeface;
|
||||
@@ -25,6 +26,7 @@ import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.positions.services.MainService;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -59,9 +61,13 @@ public class App extends GlobalApplication {
|
||||
//===================== 全局静态常量与变量 =====================
|
||||
public static final String TAG = "App";
|
||||
private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper());
|
||||
private static App sInstance;
|
||||
|
||||
private static final String SP_NAME = "app_idle_config";
|
||||
private static final String SP_KEY_IDLE_RUNNING = "is_idle_running";
|
||||
|
||||
// 应用全局空转状态标记
|
||||
public static boolean isAppIdleRunning = false;
|
||||
private static boolean isAppIdleRunning = false;
|
||||
|
||||
//===================== 空转状态对外方法 =====================
|
||||
/**
|
||||
@@ -83,23 +89,67 @@ public class App extends GlobalApplication {
|
||||
LogUtils.d(TAG, "setAppIdleRunning -> 传入参数 idleRunning = " + idleRunning);
|
||||
if (isDebugging()) {
|
||||
isAppIdleRunning = idleRunning;
|
||||
LogUtils.i(TAG, "setAppIdleRunning -> 调试模式,空转状态设置生效");
|
||||
saveIdleRunningToSp(idleRunning);
|
||||
LogUtils.i(TAG, "setAppIdleRunning -> 调试模式,空转状态设置生效并持久化");
|
||||
|
||||
// 重启MainService服务以同步新的空转状态(stopService对未运行服务无效,故无需判断状态)
|
||||
if (sInstance != null) {
|
||||
LogUtils.i(TAG, "setAppIdleRunning -> 重启MainService服务以同步空转状态");
|
||||
Intent serviceIntent = new Intent(sInstance, MainService.class);
|
||||
sInstance.stopService(serviceIntent);
|
||||
sInstance.startService(serviceIntent);
|
||||
}
|
||||
} else {
|
||||
LogUtils.i(TAG, "setAppIdleRunning -> 非调试模式,空转设置无效");
|
||||
LogUtils.i(TAG, "Non-debug state, app idle setting is meaningless.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从SharedPreferences加载空转状态
|
||||
*/
|
||||
private static void loadIdleRunningFromSp() {
|
||||
try {
|
||||
if (sInstance != null) {
|
||||
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
isAppIdleRunning = sp.getBoolean(SP_KEY_IDLE_RUNNING, false);
|
||||
LogUtils.i(TAG, "loadIdleRunningFromSp -> 从SP加载空转状态:" + isAppIdleRunning);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "loadIdleRunningFromSp -> 加载空转状态失败:" + e.getMessage());
|
||||
isAppIdleRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存空转状态到SharedPreferences
|
||||
* @param idleRunning 空转状态
|
||||
*/
|
||||
private static void saveIdleRunningToSp(boolean idleRunning) {
|
||||
try {
|
||||
if (sInstance != null) {
|
||||
SharedPreferences sp = sInstance.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
sp.edit().putBoolean(SP_KEY_IDLE_RUNNING, idleRunning).apply();
|
||||
LogUtils.i(TAG, "saveIdleRunningToSp -> 空转状态已保存:" + idleRunning);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "saveIdleRunningToSp -> 保存空转状态失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
//===================== 应用生命周期 =====================
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
sInstance = this;
|
||||
LogUtils.i(TAG, "onCreate -> 全局Application初始化开始");
|
||||
|
||||
setIsDebugging(BuildConfig.DEBUG);
|
||||
WinBoLLActivityManager.init(this);
|
||||
ToastUtils.init(this);
|
||||
|
||||
loadIdleRunningFromSp();
|
||||
|
||||
LogUtils.i(TAG, "onCreate -> 全局组件初始化全部完成");
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,15 @@ import cc.winboll.studio.positions.handlers.AppIdleRunningModeHandler;
|
||||
import cc.winboll.studio.positions.utils.AppConfigsUtil;
|
||||
import cc.winboll.studio.positions.utils.ServiceUtil;
|
||||
import cc.winboll.studio.positions.services.IdleGpsService;
|
||||
import cc.winboll.studio.positions.services.MainService;
|
||||
import cc.winboll.studio.positions.R;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Handler;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
|
||||
/**
|
||||
* 主页面控制器
|
||||
@@ -345,11 +353,6 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
|
||||
boolean idleNow = App.isAppIdleRunning();
|
||||
boolean idleNew = !idleNow;
|
||||
App.setAppIdleRunning(idleNew);
|
||||
if (idleNew) {
|
||||
IdleGpsService.getInstance().start();
|
||||
} else {
|
||||
IdleGpsService.getInstance().stop();
|
||||
}
|
||||
AppIdleRunningModeHandler.sendIdleSwitch(idleNew);
|
||||
AppIdleRunningModeHandler.sendIdleLog("菜单手动切换空转状态:" + idleNew);
|
||||
LogUtils.d(TAG, "onOptionsItemSelected -> 空转状态已切换,当前:" + idleNew);
|
||||
|
||||
@@ -3,6 +3,7 @@ package cc.winboll.studio.positions.services;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.positions.handlers.AppIdleRunningModeHandler;
|
||||
import cc.winboll.studio.positions.models.PositionModel;
|
||||
|
||||
@@ -100,6 +101,7 @@ public class IdleGpsService {
|
||||
currentBearing = 1;
|
||||
AppIdleRunningModeHandler.sendIdleLog("空转GPS服务已启动");
|
||||
notifyStatusChange("空转GPS服务已启动");
|
||||
ToastUtils.show("空转GPS服务已启动");
|
||||
handler.post(updateRunnable);
|
||||
handler.post(bearingRunnable);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ 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.App;
|
||||
import cc.winboll.studio.positions.models.PositionModel;
|
||||
import cc.winboll.studio.positions.models.PositionTaskModel;
|
||||
import cc.winboll.studio.positions.utils.AppConfigsUtil;
|
||||
@@ -54,6 +55,35 @@ public class MainService extends Service {
|
||||
void onGpsStatusChanged(String status);
|
||||
}
|
||||
|
||||
// 空转GPS监听实例(用于注册到IdleGpsService)
|
||||
private final GpsUpdateListener mIdleGpsListener = new GpsUpdateListener() {
|
||||
@Override
|
||||
public void onGpsPositionUpdated(PositionModel currentGpsPos) {
|
||||
handleGpsPositionUpdate(currentGpsPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGpsStatusChanged(String status) {
|
||||
handleGpsStatusChange(status);
|
||||
}
|
||||
};
|
||||
|
||||
// 中央处理:GPS 位置更新
|
||||
private void handleGpsPositionUpdate(PositionModel pos) {
|
||||
if (pos == null) return;
|
||||
syncCurrentGpsPosition(pos);
|
||||
DistanceCalculatorUtil.getInstance(MainService.this).checkAllTaskTriggerCondition(pos);
|
||||
String src = App.isAppIdleRunning() ? " (空转)" : "";
|
||||
LogUtils.d(TAG, "GPS位置更新:纬度=" + pos.getLatitude() + ",经度=" + pos.getLongitude() + src);
|
||||
}
|
||||
|
||||
// 中央处理:GPS 状态变化
|
||||
private void handleGpsStatusChange(String status) {
|
||||
LogUtils.d(TAG, "GPS状态变化:" + status);
|
||||
notifyAllGpsStatusListeners(status);
|
||||
updateNotificationGpsStatus(status);
|
||||
}
|
||||
|
||||
// 任务更新监听接口(Java 7 风格,供Adapter监听任务变化)
|
||||
public interface TaskUpdateListener {
|
||||
void onTaskUpdated();
|
||||
@@ -77,6 +107,7 @@ public class MainService extends Service {
|
||||
private final ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>(); // 位置数据列表
|
||||
private final ArrayList<PositionTaskModel> mAllTasks = new ArrayList<PositionTaskModel>();// 任务数据列表
|
||||
private static PositionModel _mCurrentGpsPosition; // 当前GPS定位数据
|
||||
private boolean isListeningToIdleGps = false; // 当前是否监听空转GPS
|
||||
|
||||
// 服务相关变量(Java 7 显式声明,保持原逻辑)
|
||||
MyServiceConnection mMyServiceConnection;
|
||||
@@ -366,6 +397,9 @@ public class MainService extends Service {
|
||||
}
|
||||
|
||||
if (mAppConfigsUtil.isEnableMainService(true)) {
|
||||
if (App.isAppIdleRunning()) {
|
||||
IdleGpsService.getInstance().start();
|
||||
}
|
||||
run(); // 启动服务核心逻辑
|
||||
}
|
||||
}
|
||||
@@ -382,6 +416,9 @@ public class MainService extends Service {
|
||||
|
||||
// 启动前台服务(Java 7 显式调用,无方法引用)
|
||||
String initialStatus = "[ Positions ] is in Service.";
|
||||
if (App.isAppIdleRunning()) {
|
||||
initialStatus += " [IDLE RUNNING]";
|
||||
}
|
||||
NotificationUtil.createForegroundServiceNotification(this, initialStatus);
|
||||
startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID,
|
||||
NotificationUtil.createForegroundServiceNotification(this, initialStatus));
|
||||
@@ -599,21 +636,28 @@ public class MainService extends Service {
|
||||
if (!_mIsServiceRunning || _mCurrentGpsPosition == null) {
|
||||
return;
|
||||
}
|
||||
// 格式化通知内容(Java 7 String.format,无String.join等Java 8+方法)
|
||||
final String gpsStatus = String.format(
|
||||
"GPS位置:北纬%.4f° 东经%.4f° | 可见位置:%d个",
|
||||
// 根据空转状态决定通知前缀(区分空转GPS与真实GPS)
|
||||
String prefix = App.isAppIdleRunning() ? "空转GPS" : "GPS位置";
|
||||
// 格式化通知内容(Java 7 String.format,使用%.15f显示全部GPS精度)
|
||||
String gpsStatus = String.format(
|
||||
"%s:北纬%.15f° 东经%.15f° | 可见位置:%d个",
|
||||
prefix,
|
||||
_mCurrentGpsPosition.getLatitude(),
|
||||
_mCurrentGpsPosition.getLongitude(),
|
||||
mVisiblePositionIds.size()
|
||||
);
|
||||
if (App.isAppIdleRunning()) {
|
||||
gpsStatus += " [IDLE RUNNING]";
|
||||
}
|
||||
final String finalGpsStatus = gpsStatus;
|
||||
// 主线程判断+切换(Java 7 匿名内部类)
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
NotificationUtil.updateForegroundServiceStatus(this, gpsStatus);
|
||||
NotificationUtil.updateForegroundServiceStatus(this, finalGpsStatus);
|
||||
} else {
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationUtil.updateForegroundServiceStatus(MainService.this, gpsStatus);
|
||||
NotificationUtil.updateForegroundServiceStatus(MainService.this, finalGpsStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -634,6 +678,9 @@ public class MainService extends Service {
|
||||
if (intent != null) {
|
||||
isSettingToEnable = intent.getBooleanExtra(EXTRA_IS_SETTING_TO_ENABLE, false);
|
||||
if (isSettingToEnable) {
|
||||
if (App.isAppIdleRunning()) {
|
||||
IdleGpsService.getInstance().start();
|
||||
}
|
||||
run(); // 重启服务核心逻辑(保证服务启动后进入运行状态)
|
||||
}
|
||||
}
|
||||
@@ -701,10 +748,8 @@ public class MainService extends Service {
|
||||
gpsPos.setPositionId("CURRENT_GPS_POS");
|
||||
gpsPos.setMemo("实时GPS位置");
|
||||
|
||||
// 同步GPS位置+刷新距离+日志(原逻辑保留)
|
||||
syncCurrentGpsPosition(gpsPos);
|
||||
DistanceCalculatorUtil.getInstance(MainService.this).checkAllTaskTriggerCondition(gpsPos);
|
||||
LogUtils.d(TAG, "GPS位置更新:纬度=" + location.getLatitude() + ",经度=" + location.getLongitude());
|
||||
// 调用中央处理方法
|
||||
handleGpsPositionUpdate(gpsPos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,9 +770,7 @@ public class MainService extends Service {
|
||||
statusDesc = "GPS状态:临时不可用(遮挡)";
|
||||
break;
|
||||
}
|
||||
LogUtils.d(TAG, statusDesc);
|
||||
notifyAllGpsStatusListeners(statusDesc);
|
||||
updateNotificationGpsStatus(statusDesc);
|
||||
handleGpsStatusChange(statusDesc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -736,10 +779,7 @@ public class MainService extends Service {
|
||||
// GPS启用时更新状态+通知+重启定位(Java 7 基础逻辑)
|
||||
if (provider.equals(LocationManager.GPS_PROVIDER)) {
|
||||
isGpsEnabled = true;
|
||||
String statusDesc = "GPS已开启(用户手动打开)";
|
||||
LogUtils.d(TAG, statusDesc);
|
||||
notifyAllGpsStatusListeners(statusDesc);
|
||||
updateNotificationGpsStatus("GPS已开启,正在获取位置...");
|
||||
handleGpsStatusChange("GPS已开启(用户手动打开)");
|
||||
startGpsLocation();
|
||||
}
|
||||
}
|
||||
@@ -750,10 +790,7 @@ public class MainService extends Service {
|
||||
if (provider.equals(LocationManager.GPS_PROVIDER)) {
|
||||
isGpsEnabled = false;
|
||||
_mCurrentGpsPosition = null;
|
||||
String statusDesc = "GPS已关闭(用户手动关闭)";
|
||||
LogUtils.w(TAG, statusDesc);
|
||||
notifyAllGpsStatusListeners(statusDesc);
|
||||
updateNotificationGpsStatus("GPS已关闭,请在设置中开启");
|
||||
handleGpsStatusChange("GPS已关闭(用户手动关闭)");
|
||||
ToastUtils.show("GPS已关闭,无法获取位置,请在设置中开启");
|
||||
}
|
||||
}
|
||||
@@ -801,8 +838,27 @@ public class MainService extends Service {
|
||||
|
||||
/**
|
||||
* 启动GPS定位(Java 7 异常处理,无try-with-resources,显式捕获SecurityException)
|
||||
* 【关键修改】根据应用空转状态切换数据源(IdleGpsService 或 系统GPS)
|
||||
*/
|
||||
private void startGpsLocation() {
|
||||
// 检查空转状态:如果处于空转,使用 IdleGpsService
|
||||
if (App.isAppIdleRunning()) {
|
||||
if (isListeningToIdleGps) return; // 已在监听空转GPS,无需重复注册
|
||||
stopGpsLocation(); // 停止系统GPS监听(如果正在运行)
|
||||
IdleGpsService.getInstance().registerGpsUpdateListener(mIdleGpsListener);
|
||||
isListeningToIdleGps = true;
|
||||
LogUtils.d(TAG, "启动GPS定位:使用空转模拟数据");
|
||||
handleGpsStatusChange("空转GPS监听中...");
|
||||
return;
|
||||
}
|
||||
|
||||
// 系统GPS逻辑
|
||||
if (isListeningToIdleGps) {
|
||||
// 之前是空转,现在切换到系统GPS
|
||||
IdleGpsService.getInstance().unregisterGpsUpdateListener(mIdleGpsListener);
|
||||
isListeningToIdleGps = false;
|
||||
}
|
||||
|
||||
if (!checkGpsReady()) {
|
||||
return;
|
||||
}
|
||||
@@ -824,12 +880,11 @@ public class MainService extends Service {
|
||||
lastGpsPos.setLatitude(lastKnownLocation.getLatitude());
|
||||
lastGpsPos.setLongitude(lastKnownLocation.getLongitude());
|
||||
lastGpsPos.setPositionId("CURRENT_GPS_POS");
|
||||
syncCurrentGpsPosition(lastGpsPos);
|
||||
handleGpsPositionUpdate(lastGpsPos);
|
||||
LogUtils.d(TAG, "已获取缓存GPS位置:纬度=" + lastKnownLocation.getLatitude());
|
||||
} else {
|
||||
String tip = "无缓存GPS位置,等待实时定位...";
|
||||
LogUtils.d(TAG, tip);
|
||||
notifyAllGpsStatusListeners(tip);
|
||||
handleGpsStatusChange(tip);
|
||||
updateNotificationGpsStatus("GPS搜索中(请移至开阔地带)");
|
||||
}
|
||||
|
||||
@@ -837,33 +892,40 @@ public class MainService extends Service {
|
||||
// 定位权限异常(Java 7 显式捕获,无Lambda异常处理)
|
||||
String error = "启动GPS失败(权限异常):" + e.getMessage();
|
||||
LogUtils.e(TAG, error);
|
||||
notifyAllGpsStatusListeners(error);
|
||||
handleGpsStatusChange(error);
|
||||
isGpsPermissionGranted = false;
|
||||
updateNotificationGpsStatus("定位权限异常,无法获取GPS");
|
||||
} catch (Exception e) {
|
||||
// 其他异常(如LocationManager为空、系统服务异常等)
|
||||
String error = "启动GPS失败:" + e.getMessage();
|
||||
LogUtils.e(TAG, error);
|
||||
notifyAllGpsStatusListeners(error);
|
||||
handleGpsStatusChange(error);
|
||||
updateNotificationGpsStatus("GPS启动失败,尝试重试...");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止GPS定位(Java 7 异常处理,移除监听器避免内存泄漏)
|
||||
* 【关键修改】根据当前监听源停止对应的服务
|
||||
*/
|
||||
private void stopGpsLocation() {
|
||||
// 校验参数:避免空指针+权限未授予时调用
|
||||
if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) {
|
||||
try {
|
||||
mLocationManager.removeUpdates(mGpsLocationListener);
|
||||
String tip = "GPS定位已停止(移除监听器)";
|
||||
LogUtils.d(TAG, tip);
|
||||
notifyAllGpsStatusListeners(tip);
|
||||
} catch (Exception e) {
|
||||
String error = "停止GPS失败:" + e.getMessage();
|
||||
LogUtils.e(TAG, error);
|
||||
notifyAllGpsStatusListeners(error);
|
||||
if (isListeningToIdleGps) {
|
||||
IdleGpsService.getInstance().unregisterGpsUpdateListener(mIdleGpsListener);
|
||||
isListeningToIdleGps = false;
|
||||
LogUtils.d(TAG, "停止GPS定位:已注销空转GPS监听");
|
||||
} else {
|
||||
// 校验参数:避免空指针+权限未授予时调用
|
||||
if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) {
|
||||
try {
|
||||
mLocationManager.removeUpdates(mGpsLocationListener);
|
||||
String tip = "GPS定位已停止(移除监听器)";
|
||||
LogUtils.d(TAG, tip);
|
||||
handleGpsStatusChange(tip);
|
||||
} catch (Exception e) {
|
||||
String error = "停止GPS失败:" + e.getMessage();
|
||||
LogUtils.e(TAG, error);
|
||||
handleGpsStatusChange(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -915,14 +977,19 @@ public class MainService extends Service {
|
||||
*/
|
||||
void updateNotificationGpsStatus(final String statusText) {
|
||||
if (_mIsServiceRunning) {
|
||||
String text = statusText;
|
||||
if (App.isAppIdleRunning()) {
|
||||
text += " [IDLE RUNNING]";
|
||||
}
|
||||
final String finalText = text;
|
||||
// 判断当前线程是否为主线程,避免UI操作在子线程
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
NotificationUtil.updateForegroundServiceStatus(this, statusText);
|
||||
NotificationUtil.updateForegroundServiceStatus(this, finalText);
|
||||
} else {
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
NotificationUtil.updateForegroundServiceStatus(MainService.this, statusText);
|
||||
NotificationUtil.updateForegroundServiceStatus(MainService.this, finalText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user