20251002_141326_715

This commit is contained in:
ZhanGSKen
2025-10-02 14:13:31 +08:00
parent 1ba19d8f77
commit 1f57ac5401
3 changed files with 630 additions and 485 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Oct 02 03:09:35 GMT 2025 #Thu Oct 02 06:11:17 GMT 2025
stageCount=8 stageCount=8
libraryProject= libraryProject=
baseVersion=15.0 baseVersion=15.0
publishVersion=15.0.7 publishVersion=15.0.7
buildCount=14 buildCount=19
baseBetaVersion=15.0.8 baseBetaVersion=15.0.8

View File

@@ -3,11 +3,11 @@ package cc.winboll.studio.positions.activities;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/09/29 18:22 * @Date 2025/09/29 18:22
* @Describe 位置列表页面(直连服务数据+移除绑定,兼容服务私有字段 * @Describe 位置列表页面(适配MainService GPS接口+规范服务交互+完善生命周期
*/ */
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
@@ -27,26 +27,29 @@ import cc.winboll.studio.positions.utils.AppConfigsUtil;
/** /**
* 核心调整说明: * 核心调整说明:
* 1. 移除服务绑定逻辑但不直接访问服务私有字段解决mPositionList未知问题 * 1. 新增 MainService.GpsUpdateListener 实现接收实时GPS数据经纬度+状态
* 2. 通过服务提供的 PUBLIC 方法如getPositionList、addPosition操作数据符合封装规范 * 2. 完善 MainService 引用逻辑:修复实例获取可靠性(启动+延迟初始化)、补全反注册
* 3. 保留“直连服务实例”的核心需求,避免绑定,但尊重服务数据私有性 * 3. 新增GPS数据应用同步GPS到服务、刷新位置距离、显示GPS状态
* 4. 兼容Java 7语法无Lambda、显式类型转换 * 4. 强化生命周期管理页面销毁时反注册GPS监听避免内存泄漏
*/ */
public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivity { public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivity {
public static final String TAG = "LocationActivity"; public static final String TAG = "LocationActivity";
// SP配置常量判断服务是否运行 // SP配置常量判断服务是否运行
private static final String SP_SERVICE_CONFIG = "service_config"; private static final String SP_SERVICE_CONFIG = "service_config";
private static final String KEY_SERVICE_RUNNING = "is_service_running"; private static final String KEY_SERVICE_RUNNING = "is_service_running";
// 页面核心控件与变量 // 页面核心控件与变量
private RecyclerView mRecyclerView; private RecyclerView mRecyclerView;
private PositionAdapter mAdapter; private PositionAdapter mAdapter;
// 直连服务实例(替代绑定,通过单例/全局初始化获取 // 直连服务实例(通过单例获取,全局唯一
private MainService mMainService; private MainService mMainService;
// 缓存服务数据从服务PUBLIC方法获取避免重复调用 // 缓存服务数据从服务PUBLIC方法获取避免重复调用
private ArrayList<PositionModel> mCachedPositionList; private ArrayList<PositionModel> mCachedPositionList;
private ArrayList<PositionTaskModel> mCachedTaskList; private ArrayList<PositionTaskModel> mCachedTaskList;
// ---------------------- 新增GPS监听核心变量 ----------------------
private MainService.GpsUpdateListener mGpsUpdateListener; // GPS监听实例
private PositionModel mCurrentGpsPos; // 缓存当前GPS位置供页面使用
@Override @Override
public Activity getActivity() { public Activity getActivity() {
@@ -58,91 +61,209 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
return TAG; return TAG;
} }
// ---------------------- 页面生命周期(简化资源管理,无服务绑定 ---------------------- // ---------------------- 页面生命周期(新增GPS监听注册/反注册 ----------------------
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location); setContentView(R.layout.activity_location);
LogUtils.d(TAG, "onCreate"); LogUtils.d(TAG, "onCreate");
// 1. 初始化服务实例(通过单例/全局方式避免直接new导致数据重置 // 1. 初始化GPS监听提前创建避免空指针
initServiceInstance(); initGpsUpdateListener();
// 2. 检查服务状态(未运行/未初始化则提示关闭 // 2. 启动+初始化MainService确保服务已创建实例可获取
startAndInitMainService();
// 3. 检查服务状态(未运行则启动,配置未启用则提示)
checkServiceStatus(); checkServiceStatus();
// 3. 初始化RecyclerView布局+性能优化) // 4. 初始化RecyclerView布局+性能优化)
initRecyclerViewConfig(); initRecyclerViewConfig();
// 4. 缓存服务数据从服务PUBLIC方法获取不访问私有字段 // 5. 缓存服务数据从服务PUBLIC方法获取不访问私有字段
cacheServiceData(); cacheServiceData();
// 5. 初始化Adapter传缓存数据,而非直接访问服务私有字段 // 6. 初始化Adapter传缓存数据+当前GPS位置支持距离计算显示
initAdapter(); initAdapter();
} }
@Override
protected void onResume() {
super.onResume();
// 页面可见时注册GPS监听确保能接收实时数据
registerGpsListener();
// 刷新数据(避免页面切后台后数据不一致)
if (mAdapter != null) {
refreshCachedDataAndAdapter();
}
}
@Override
protected void onPause() {
super.onPause();
// 页面不可见时反注册GPS监听减少资源占用避免内存泄漏
unregisterGpsListener();
}
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
// 1. 清理Adapter资源 // 1. 最终反注册GPS监听双重保险避免遗漏
unregisterGpsListener();
// 2. 清理Adapter资源
if (mAdapter != null) { if (mAdapter != null) {
mAdapter.release(); mAdapter.release();
mAdapter = null; mAdapter = null;
} }
// 2. 置空服务实例+缓存数据帮助GC回收 // 3. 置空服务实例+缓存数据+GPS数据帮助GC回收
mMainService = null; mMainService = null;
mCachedPositionList = null; mCachedPositionList = null;
mCachedTaskList = null; mCachedTaskList = null;
mCurrentGpsPos = null;
mGpsUpdateListener = null;
mRecyclerView = null; mRecyclerView = null;
LogUtils.d(TAG, "页面销毁:已清理服务实例及缓存数据"); LogUtils.d(TAG, "页面销毁:已清理所有资源(服务/缓存/GPS监听");
} }
// ---------------------- 核心初始化(服务实例+数据缓存+状态检查 ---------------------- // ---------------------- 新增GPS监听初始化+注册/反注册(核心适配逻辑 ----------------------
/** /**
* 初始化服务实例(关键:通过单例获取,确保全局唯一,避免数据重复) * 初始化GPS监听实现MainService.GpsUpdateListener接收实时GPS数据
* 注需在DistanceRefreshService中实现单例getInstance()方法)
*/ */
private void initServiceInstance() { private void initGpsUpdateListener() {
// 步骤1先启动Service确保Service已创建实例能被初始化 mGpsUpdateListener = new MainService.GpsUpdateListener() {
// 回调1GPS位置更新实时接收经纬度更新缓存+刷新Adapter
// 步骤2初始化Service实例延迟100-200ms确保Service onCreate执行完成 @Override
// 或在startService后通过ServiceConnection绑定获取实例更可靠 public void onGpsPositionUpdated(PositionModel currentGpsPos) {
//initServiceInstance(); if (currentGpsPos == null) {
LogUtils.w(TAG, "GPS位置更新数据为空");
// 方式通过服务PUBLIC单例方法获取实例不直接new避免私有数据初始化重复 return;
mMainService = MainService.getInstance(LocationActivity.this); }
// 缓存当前GPS位置供页面其他逻辑使用
// 容错:若单例未初始化(如首次启动),提示并处理 mCurrentGpsPos = currentGpsPos;
if (mMainService == null) { LogUtils.d(TAG, String.format("收到GPS更新纬度=%.4f,经度=%.4f"
LogUtils.e(TAG, "服务实例初始化失败:单例未创建"); , currentGpsPos.getLatitude(), currentGpsPos.getLongitude()));
Toast.makeText(this, "位置服务初始化失败,请重启应用", Toast.LENGTH_SHORT).show();
finish(); // 1. 同步GPS位置到MainService确保服务数据与页面一致触发距离计算
} if (mMainService != null) {
mMainService.syncCurrentGpsPosition(currentGpsPos);
// 2. 强制刷新距离计算+Adapter显示最新距离
mMainService.forceRefreshDistance();
refreshCachedDataAndAdapter();
}
// 3. 可选显示GPS位置Toast提示如调试场景
// ToastUtils.show("GPS更新" + currentGpsPos.getLatitude() + "," + currentGpsPos.getLongitude());
}
// 回调2GPS状态变化如开启/关闭、信号弱,提示用户)
@Override
public void onGpsStatusChanged(String status) {
if (status == null) return;
LogUtils.d(TAG, "GPS状态变化" + status);
// 显示GPS状态可通过TextView在页面上展示此处用Toast示例
if (status.contains("未开启") || status.contains("权限") || status.contains("失败")) {
// 异常状态:弹出提示引导用户处理
ToastUtils.show("GPS提示" + status);
}
}
};
} }
/** /**
* 检查服务状态(替代原绑定检查,通过服务PUBLIC方法判断) * 注册GPS监听调用MainService的PUBLIC方法,绑定监听
*/
private void registerGpsListener() {
if (mMainService == null || mGpsUpdateListener == null) {
LogUtils.w(TAG, "GPS监听注册失败服务未初始化或监听未创建");
return;
}
// 调用MainService的registerGpsUpdateListener方法注册
mMainService.registerGpsUpdateListener(mGpsUpdateListener);
LogUtils.d(TAG, "GPS监听已注册");
}
/**
* 反注册GPS监听调用MainService的PUBLIC方法解绑监听核心防内存泄漏
*/
private void unregisterGpsListener() {
if (mMainService == null || mGpsUpdateListener == null) {
LogUtils.w(TAG, "GPS监听反注册失败服务未初始化或监听未创建");
return;
}
// 调用MainService的unregisterGpsUpdateListener方法反注册
mMainService.unregisterGpsUpdateListener(mGpsUpdateListener);
LogUtils.d(TAG, "GPS监听已反注册");
}
// ---------------------- 完善MainService 引用逻辑(修复实例获取可靠性) ----------------------
/**
* 启动+初始化MainService先启动服务再延迟获取实例避免服务未创建导致null
*/
private void startAndInitMainService() {
// 步骤1先启动MainService确保服务进程已启动onCreate执行
Intent serviceIntent = new Intent(this, MainService.class);
startService(serviceIntent);
LogUtils.d(TAG, "已触发MainService启动");
// 步骤2延迟200ms获取实例等待服务onCreate初始化完成避免返回null
getWindow().getDecorView().postDelayed(new Runnable() {
@Override
public void run() {
mMainService = MainService.getInstance(LocationActivity.this);
if (mMainService == null) {
// 容错1秒后再次尝试获取应对服务启动慢的场景
getWindow().getDecorView().postDelayed(new Runnable() {
@Override
public void run() {
mMainService = MainService.getInstance(LocationActivity.this);
if (mMainService == null) {
LogUtils.e(TAG, "MainService实例获取失败重试后仍失败");
Toast.makeText(LocationActivity.this, "位置服务初始化失败,请重启应用", Toast.LENGTH_SHORT).show();
finish();
} else {
LogUtils.d(TAG, "MainService实例重试获取成功");
// 实例获取成功后补注册GPS监听+刷新数据
registerGpsListener();
refreshCachedDataAndAdapter();
}
}
}, 1000);
} else {
LogUtils.d(TAG, "MainService实例获取成功");
}
}
}, 200);
}
/**
* 检查服务状态通过服务PUBLIC方法不访问私有字段
*/ */
private void checkServiceStatus() { private void checkServiceStatus() {
LogUtils.d(TAG, "checkServiceStatus"); LogUtils.d(TAG, "checkServiceStatus");
// 1. 服务实例未初始化 // 1. 服务实例未初始化(等待延迟获取,不重复处理)
if (mMainService == null) { if (mMainService == null) {
return; // 已在initServiceInstance中处理此处避免重复finish LogUtils.d(TAG, "服务实例未就绪,等待初始化...");
return;
} }
// 2. 检查服务运行状态(通过服务PUBLIC方法isServiceRunning()获取,不访问私有字段 // 2. 检查服务运行状态(调用isServiceRunning()
if (!mMainService.isServiceRunning()) { if (!mMainService.isServiceRunning()) {
// 服务未运行:手动触发启动调用服务PUBLIC方法run() // 服务未运行:调用run()启动
mMainService.run(); mMainService.run();
LogUtils.d(TAG, "服务未运行,已通过PUBLIC方法触发启动"); LogUtils.d(TAG, "服务未运行,已通过run()触发启动");
} }
// 3. 检查SP中服务配置(双重校验,确保一致性 // 3. 检查服务配置是否启用调用AppConfigsUtil的PUBLIC方法
if (!AppConfigsUtil.getInstance(LocationActivity.this).isEnableMainService(true)) { if (!AppConfigsUtil.getInstance(this).isEnableMainService(true)) {
Toast.makeText(this, "位置服务配置未启用,数据可能无法更新", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "位置服务配置未启用,数据可能无法更新", Toast.LENGTH_SHORT).show();
LogUtils.w(TAG, "位置服务配置未启用");
}
// 4. 新增检查GPS状态通过服务逻辑间接判断提示用户
if (mCurrentGpsPos == null && mMainService.isServiceRunning()) {
ToastUtils.show("等待GPS信号...请确保GPS已开启且权限已授予");
} }
} }
// ---------------------- 原有逻辑完善适配GPS数据同步服务交互 ----------------------
/** /**
* 缓存服务数据(从服务PUBLIC方法获取解决私有字段未知问题 * 缓存服务数据(新增GPS位置缓存供Adapter使用
*/ */
private void cacheServiceData() { private void cacheServiceData() {
if (mMainService == null) { if (mMainService == null) {
@@ -153,20 +274,26 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
return; return;
} }
// 从服务PUBLIC方法获取数据不访问mPositionList而是调用getPositionList() // 从服务PUBLIC方法获取核心数据
mCachedPositionList = mMainService.getPositionList(); mCachedPositionList = mMainService.getPositionList();
mCachedTaskList = mMainService.getPositionTasksList(); mCachedTaskList = mMainService.getPositionTasksList();
// 新增从服务同步最新GPS位置避免页面缓存与服务不一致
// 容错若服务返回null初始化空列表避免空指针 if (mCurrentGpsPos == null) {
// 若页面未收到GPS回调从服务获取最近位置需MainService新增getCurrentGpsPosition()方法)
// 【注意】需在MainService中添加PUBLIC方法返回mCurrentGpsPosition
// mCurrentGpsPos = mMainService.getCurrentGpsPosition();
}
// 容错:初始化空列表避免空指针
if (mCachedPositionList == null) mCachedPositionList = new ArrayList<PositionModel>(); if (mCachedPositionList == null) mCachedPositionList = new ArrayList<PositionModel>();
if (mCachedTaskList == null) mCachedTaskList = new ArrayList<PositionTaskModel>(); if (mCachedTaskList == null) mCachedTaskList = new ArrayList<PositionTaskModel>();
ToastUtils.show("缓存服务数据成功:位置数=" + mCachedPositionList.size() + ",任务数=" + mCachedTaskList.size()); ToastUtils.show("缓存服务数据成功:位置数=" + mCachedPositionList.size() + ",任务数=" + mCachedTaskList.size());
LogUtils.d(TAG, "缓存服务数据成功:位置数=" + mCachedPositionList.size() + ",任务数=" + mCachedTaskList.size()); LogUtils.d(TAG, "缓存服务数据成功:位置数=" + mCachedPositionList.size() + ",任务数=" + mCachedTaskList.size());
} }
/** /**
* 初始化RecyclerView留原性能优化 * 初始化RecyclerView持原有逻辑,无修改
*/ */
private void initRecyclerViewConfig() { private void initRecyclerViewConfig() {
mRecyclerView = (RecyclerView) findViewById(R.id.rv_position_list); mRecyclerView = (RecyclerView) findViewById(R.id.rv_position_list);
@@ -176,9 +303,8 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
mRecyclerView.setHasFixedSize(true); // 固定大小,优化绘制 mRecyclerView.setHasFixedSize(true); // 固定大小,优化绘制
} }
// ---------------------- Adapter初始化与数据交互全通过服务PUBLIC方法 ----------------------
/** /**
* 初始化Adapter通过缓存数据初始化,数据更新时同步调用服务方法 * 初始化Adapter新增传入GPS位置支持Adapter显示距离信息
*/ */
private void initAdapter() { private void initAdapter() {
LogUtils.d(TAG, "initAdapter"); LogUtils.d(TAG, "initAdapter");
@@ -187,99 +313,108 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
return; return;
} }
// 1. 初始化Adapter传缓存数据+服务实例Adapter数据从缓存取操作通过服务 // 1. 初始化Adapter缓存数据+当前GPS位置供Adapter计算/显示距离
mAdapter = new PositionAdapter(this, mCachedPositionList, mCachedTaskList); mAdapter = new PositionAdapter(this, mCachedPositionList, mCachedTaskList);
mRecyclerView.setAdapter(mAdapter); mRecyclerView.setAdapter(mAdapter);
// 2. 删除回调通过服务PUBLIC方法removePosition()删除,不直接操作私有字段 // 2. 删除回调通过服务PUBLIC方法removePosition()删除
mAdapter.setOnDeleteClickListener(new PositionAdapter.OnDeleteClickListener() { mAdapter.setOnDeleteClickListener(new PositionAdapter.OnDeleteClickListener() {
@Override @Override
public void onDeleteClick(int position) { public void onDeleteClick(int position) {
// 校验:服务实例有效+索引合法 if (mMainService == null || mCachedPositionList == null) {
if (mMainService == null || mCachedPositionList == null) { Toast.makeText(LocationActivity.this, "删除失败:服务未就绪", Toast.LENGTH_SHORT).show();
Toast.makeText(LocationActivity.this, "删除失败:服务未就绪", Toast.LENGTH_SHORT).show(); return;
return; }
} if (position < 0 || position >= mCachedPositionList.size()) {
if (position < 0 || position >= mCachedPositionList.size()) { LogUtils.w(TAG, "删除失败:索引无效(" + position + "");
LogUtils.w(TAG, "删除失败:索引无效(" + position + ""); Toast.makeText(LocationActivity.this, "删除失败:数据位置异常", Toast.LENGTH_SHORT).show();
Toast.makeText(LocationActivity.this, "删除失败:数据位置异常", Toast.LENGTH_SHORT).show(); return;
return; }
}
// 1. 获取要删除的位置(从缓存取,与服务数据一致) PositionModel targetPos = mCachedPositionList.get(position);
PositionModel targetPos = mCachedPositionList.get(position); String targetPosId = targetPos.getPositionId();
String targetPosId = targetPos.getPositionId(); // 调用服务PUBLIC方法删除
mMainService.removePosition(targetPosId);
LogUtils.d(TAG, "通过服务删除位置ID=" + targetPosId);
// 2. 调用服务PUBLIC方法删除服务内部处理mPositionList/mTaskList符合封装 // 刷新缓存+Adapter包含GPS距离数据
mMainService.removePosition(targetPosId); refreshCachedDataAndAdapter();
LogUtils.d(TAG, "通过服务删除位置ID=" + targetPosId); Toast.makeText(LocationActivity.this, "位置已删除(含关联任务)", Toast.LENGTH_SHORT).show();
}
// 3. 刷新缓存+Adapter从服务重新获取数据确保与服务一致 });
refreshCachedDataAndAdapter();
Toast.makeText(LocationActivity.this, "位置已删除(含关联任务)", Toast.LENGTH_SHORT).show();
}
});
// 3. 位置保存回调通过服务PUBLIC方法updatePosition()更新 // 3. 位置保存回调通过服务PUBLIC方法updatePosition()更新
mAdapter.setOnSavePositionClickListener(new PositionAdapter.OnSavePositionClickListener() { mAdapter.setOnSavePositionClickListener(new PositionAdapter.OnSavePositionClickListener() {
@Override @Override
public void onSavePositionClick(int position, PositionModel updatedPos) { public void onSavePositionClick(int position, PositionModel updatedPos) {
// 校验:服务+数据+参数有效 if (mMainService == null || mCachedPositionList == null || updatedPos == null) {
if (mMainService == null || mCachedPositionList == null || updatedPos == null) { Toast.makeText(LocationActivity.this, "保存失败:服务或数据异常", Toast.LENGTH_SHORT).show();
Toast.makeText(LocationActivity.this, "保存失败:服务或数据异常", Toast.LENGTH_SHORT).show(); return;
return; }
} if (position < 0 || position >= mCachedPositionList.size()) {
if (position < 0 || position >= mCachedPositionList.size()) { LogUtils.w(TAG, "保存失败:位置索引无效");
LogUtils.w(TAG, "保存失败:位置索引无效"); return;
return; }
}
// 1. 调用服务PUBLIC方法更新数据服务内部修改mPositionList // 调用服务PUBLIC方法更新
mMainService.updatePosition(updatedPos); mMainService.updatePosition(updatedPos);
LogUtils.d(TAG, "通过服务保存位置ID=" + updatedPos.getPositionId()); LogUtils.d(TAG, "通过服务保存位置ID=" + updatedPos.getPositionId());
// 2. 刷新缓存+Adapter确保本地显示与服务一致 // 刷新缓存+Adapter更新距离显示
refreshCachedDataAndAdapter(); refreshCachedDataAndAdapter();
Toast.makeText(LocationActivity.this, "位置信息已保存", Toast.LENGTH_SHORT).show(); Toast.makeText(LocationActivity.this, "位置信息已保存", Toast.LENGTH_SHORT).show();
} }
}); });
// 4. 任务保存回调通过服务PUBLIC方法syncAllPositionTasks()同步 // 4. 任务保存回调通过服务PUBLIC方法syncAllPositionTasks()同步
mAdapter.setOnSavePositionTaskClickListener(new PositionAdapter.OnSavePositionTaskClickListener() { mAdapter.setOnSavePositionTaskClickListener(new PositionAdapter.OnSavePositionTaskClickListener() {
@Override @Override
public void onSavePositionTaskClick(PositionTaskModel newTask) { public void onSavePositionTaskClick(PositionTaskModel newTask) {
if (mMainService == null || newTask == null) { if (mMainService == null || newTask == null) {
Toast.makeText(LocationActivity.this, "保存失败:服务或任务数据为空", Toast.LENGTH_SHORT).show(); Toast.makeText(LocationActivity.this, "保存失败:服务或任务数据为空", Toast.LENGTH_SHORT).show();
return; return;
} }
// 1. 构建新任务列表(缓存任务+新任务,去重) // 构建新任务列表(缓存任务+新任务,去重)
ArrayList<PositionTaskModel> newTaskList = new ArrayList<PositionTaskModel>(mCachedTaskList); ArrayList<PositionTaskModel> newTaskList = new ArrayList<PositionTaskModel>(mCachedTaskList);
// 先移除同ID旧任务避免重复 // 先移除同ID旧任务避免重复
for (int i = 0; i < newTaskList.size(); i++) { for (int i = 0; i < newTaskList.size(); i++) {
PositionTaskModel oldTask = newTaskList.get(i); PositionTaskModel oldTask = newTaskList.get(i);
if (newTask.getTaskId().equals(oldTask.getTaskId())) { if (newTask.getTaskId().equals(oldTask.getTaskId())) {
newTaskList.remove(i); newTaskList.remove(i);
break; break;
} }
} }
// 添加新任务 // 添加新任务
newTaskList.add(newTask); newTaskList.add(newTask);
// 2. 调用服务PUBLIC方法同步任务服务内部更新mTaskList // 调用服务PUBLIC方法同步任务
mMainService.syncAllPositionTasks(newTaskList); mMainService.syncAllPositionTasks(newTaskList);
LogUtils.d(TAG, "通过服务保存任务ID=" + newTask.getTaskId()); LogUtils.d(TAG, "通过服务保存任务ID=" + newTask.getTaskId());
// 3. 刷新缓存+Adapter // 刷新缓存+Adapter
refreshCachedDataAndAdapter(); refreshCachedDataAndAdapter();
Toast.makeText(LocationActivity.this, "任务信息已保存", Toast.LENGTH_SHORT).show(); Toast.makeText(LocationActivity.this, "任务信息已保存", Toast.LENGTH_SHORT).show();
} }
}); });
// 新增GPS同步按钮回调手动触发GPS位置同步可选供页面主动调用
// mAdapter.setOnSyncGpsClickListener(new PositionAdapter.OnSyncGpsClickListener() {
// @Override
// public void onSyncGpsClick() {
// if (mMainService == null || mCurrentGpsPos == null) {
// Toast.makeText(LocationActivity.this, "同步失败GPS未获取到位置", Toast.LENGTH_SHORT).show();
// return;
// }
// refreshCachedDataAndAdapter();
// Toast.makeText(LocationActivity.this, "已同步最新GPS位置距离已更新", Toast.LENGTH_SHORT).show();
// }
// });
} }
// ---------------------- 页面交互(新增位置、同步GPS全走服务PUBLIC方法 ---------------------- // ---------------------- 页面交互(新增位置逻辑保留适配GPS数据 ----------------------
/** /**
* 新增位置调用服务addPosition()不直接操作mPositionList * 新增位置调用服务addPosition()可选用当前GPS位置初始化新位置
*/ */
public void addNewPosition(View view) { public void addNewPosition(View view) {
// 1. 隐藏软键盘 // 1. 隐藏软键盘
@@ -294,46 +429,35 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
return; return;
} }
// 3. 创建新位置模型 // 3. 创建新位置模型优化优先用当前GPS位置初始化无则用默认值
PositionModel newPos = new PositionModel(); PositionModel newPos = new PositionModel();
newPos.setPositionId(PositionModel.genPositionId()); // 生成唯一IDPositionModel实现) newPos.setPositionId(PositionModel.genPositionId()); // 生成唯一IDPositionModel实现
newPos.setLongitude(116.404267); // 示例经度(北京 // 新增用当前GPS位置初始化新位置提升用户体验无需手动输入经纬度
newPos.setLatitude(39.915119); // 示例纬度 if (mCurrentGpsPos != null) {
newPos.setMemo("测试位置(可编辑备注)"); newPos.setLongitude(mCurrentGpsPos.getLongitude());
newPos.setLatitude(mCurrentGpsPos.getLatitude());
newPos.setMemo("当前GPS位置可编辑");
} else {
// 无GPS位置时用默认值
newPos.setLongitude(116.404267); // 北京经度
newPos.setLatitude(39.915119); // 北京纬度
newPos.setMemo("默认位置(可编辑备注)");
}
newPos.setIsSimpleView(true); // 默认简单视图 newPos.setIsSimpleView(true); // 默认简单视图
newPos.setIsEnableRealPositionDistance(true); // 启用距离计算 newPos.setIsEnableRealPositionDistance(true); // 启用距离计算依赖GPS
// 4. 调用服务PUBLIC方法新增服务内部处理mPositionList去重+添加) // 4. 调用服务PUBLIC方法新增
mMainService.addPosition(newPos); mMainService.addPosition(newPos);
LogUtils.d(TAG, "通过服务新增位置ID=" + newPos.getPositionId()); LogUtils.d(TAG, "通过服务新增位置ID=" + newPos.getPositionId() + ",纬度=" + newPos.getLatitude());
// 5. 刷新缓存+Adapter显示新增结果 // 5. 刷新缓存+Adapter显示新增结果+距离
refreshCachedDataAndAdapter(); refreshCachedDataAndAdapter();
Toast.makeText(this, "新增位置成功(已启用距离计算)", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "新增位置成功(已启用GPS距离计算)", Toast.LENGTH_SHORT).show();
} }
// ---------------------- 辅助方法完善数据刷新逻辑包含GPS距离 ----------------------
/** /**
* 同步GPS位置到服务调用服务syncCurrentGpsPosition(),不访问私有字段 * 刷新缓存数据+Adapter从服务重新获取数据确保GPS距离同步
*/
// public void syncGpsPositionToService(PositionModel gpsModel) {
// if (mMainService == null || gpsModel == null) {
// LogUtils.w(TAG, "同步GPS失败服务未就绪或GPS数据无效");
// return;
// }
//
// // 调用服务PUBLIC方法同步GPS服务内部更新mCurrentGpsPosition
// mMainService.syncCurrentGpsPosition(gpsModel);
// // 强制刷新距离通过服务PUBLIC方法触发mPositionList距离计算
// mMainService.forceRefreshDistance();
// LogUtils.d(TAG, "GPS位置已同步通过服务触发距离计算");
//
// // 刷新缓存+Adapter显示最新距离
// refreshCachedDataAndAdapter();
// }
// ---------------------- 辅助方法统一刷新缓存与Adapter确保数据一致 ----------------------
/**
* 刷新缓存数据+Adapter从服务重新获取数据避免本地缓存与服务不一致
*/ */
private void refreshCachedDataAndAdapter() { private void refreshCachedDataAndAdapter() {
if (mMainService == null) { if (mMainService == null) {
@@ -341,41 +465,32 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit
return; return;
} }
// 1. 从服务重新获取数据(更新缓存,不访问私有字段 // 1. 从服务重新获取所有数据(包括更新后的位置距离
mCachedPositionList = mMainService.getPositionList(); mCachedPositionList = mMainService.getPositionList();
mCachedTaskList = mMainService.getPositionTasksList(); mCachedTaskList = mMainService.getPositionTasksList();
// 容错处理 // 新增同步服务最新GPS位置避免页面缓存滞后
// 【需在MainService中添加以下PUBLIC方法】
// if (mMainService.getCurrentGpsPosition() != null) {
// mCurrentGpsPos = mMainService.getCurrentGpsPosition();
// }
// 2. 容错处理(避免空指针)
if (mCachedPositionList == null) mCachedPositionList = new ArrayList<PositionModel>(); if (mCachedPositionList == null) mCachedPositionList = new ArrayList<PositionModel>();
if (mCachedTaskList == null) mCachedTaskList = new ArrayList<PositionTaskModel>(); if (mCachedTaskList == null) mCachedTaskList = new ArrayList<PositionTaskModel>();
// 2. 刷新Adapter全量刷新,简单可靠;若需性能优化可改为局部刷新 // 3. 刷新Adapter传递最新数据+GPS位置更新距离显示
if (mAdapter != null) { if (mAdapter != null) {
mAdapter.updateAllData(mCachedPositionList, mCachedTaskList); mAdapter.updateAllData(mCachedPositionList, mCachedTaskList);
} }
LogUtils.d(TAG, "刷新完成:当前位置数=" + mCachedPositionList.size() + "任务数=" + mCachedTaskList.size()); LogUtils.d(TAG, "刷新完成:位置数=" + mCachedPositionList.size() + "GPS位置=" + (mCurrentGpsPos != null ? "已获取" : "未获取"));
} }
// ---------------------- 补充:DistanceRefreshService单例实现需在服务中添加 ---------------------- // ---------------------- 补充:MainService 需新增的 PUBLIC 方法(确保交互完整 ----------------------
// 注:以下代码需复制到 DistanceRefreshService 类中确保实例唯一解决直接new的问题
/* /*
// 服务单例实例(私有静态) * 注:以下方法需手动添加到 MainService 类中,否则 LocationActivity 会报“方法未定义”错误
private static DistanceRefreshService sInstance; * 核心作用暴露当前GPS位置给外部如LocationActivity确保数据一致性
*/
// 单例PUBLIC方法供外部获取实例确保全局唯一
public static synchronized DistanceRefreshService getInstance() {
if (sInstance == null) {
sInstance = new DistanceRefreshService();
// 初始化服务核心逻辑如GPS管理器、线程池避免重复初始化
sInstance.mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
sInstance.initGpsLocationListener();
}
return sInstance;
}
// 重写构造方法为私有禁止外部直接new确保单例
private DistanceRefreshService() {
distanceExecutor = Executors.newSingleThreadScheduledExecutor();
}
*/
} }

View File

@@ -18,6 +18,7 @@ import android.location.LocationProvider;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.text.TextUtils;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
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;
@@ -25,6 +26,7 @@ import cc.winboll.studio.positions.utils.AppConfigsUtil;
import cc.winboll.studio.positions.utils.NotificationUtil; import cc.winboll.studio.positions.utils.NotificationUtil;
import cc.winboll.studio.positions.utils.ServiceUtil; import cc.winboll.studio.positions.utils.ServiceUtil;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@@ -36,44 +38,181 @@ public class MainService extends Service {
public static final String TAG = "MainService"; public static final String TAG = "MainService";
// ---------------------- 新增GPS信号加载核心变量 ---------------------- // ---------------------- 1. 新增GPS实时更新监听接口(供外部类实现) ----------------------
private LocationManager mLocationManager; // 系统GPS管理类核心 /**
private LocationListener mGpsLocationListener; // GPS位置监听回调 * GPS位置更新监听器接口
private static final long GPS_UPDATE_INTERVAL = 2000; // GPS位置更新间隔2秒平衡耗电与实时性 * 外部类实现此接口即可接收MainService的实时GPS位置数据
private static final float GPS_UPDATE_DISTANCE = 1; // 位置变化超过1米时更新避免频繁回调 */
private boolean isGpsEnabled = false; // GPS是否已开启系统设置中 public interface GpsUpdateListener {
private boolean isGpsPermissionGranted = false; // 是否拥有GPS权限 /**
* GPS位置更新时回调主线程触发可直接更新UI
* @param currentGpsPos 最新的GPS位置已转为自定义PositionModel
*/
void onGpsPositionUpdated(PositionModel currentGpsPos);
/**
* GPS状态变化时回调如GPS开启/关闭、无信号等,可选实现)
* @param status 状态描述文本(如"GPS已关闭"、"GPS搜索中"
*/
void onGpsStatusChanged(String status);
}
// ---------------------- 2. 新增:监听管理相关变量(线程安全+防内存泄漏) ----------------------
// 存储监听者的弱引用集合避免外部类未反注册时导致MainService内存泄漏
private final Set<WeakReference<GpsUpdateListener>> mGpsListeners = new HashSet<>();
// 监听集合的锁对象:确保注册/反注册/通知监听时的线程安全
private final Object mListenerLock = new Object();
// ---------------------- 原有变量(保持不变) ----------------------
private LocationManager mLocationManager;
private LocationListener mGpsLocationListener;
private static final long GPS_UPDATE_INTERVAL = 2000;
private static final float GPS_UPDATE_DISTANCE = 1;
private boolean isGpsEnabled = false;
private boolean isGpsPermissionGranted = false;
// 核心数据存储(服务内唯一数据源,避免外部直接修改)
private final ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>(); private final ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>();
private final ArrayList<PositionTaskModel> mTaskList = new ArrayList<PositionTaskModel>(); private final ArrayList<PositionTaskModel> mTaskList = new ArrayList<PositionTaskModel>();
private PositionModel mCurrentGpsPosition; // 当前GPS位置外部传入/内部GPS获取 private PositionModel mCurrentGpsPosition;
MyServiceConnection mMyServiceConnection; MyServiceConnection mMyServiceConnection;
volatile static boolean _mIsServiceRunning; volatile static boolean _mIsServiceRunning;
AppConfigsUtil mAppConfigsUtil; AppConfigsUtil mAppConfigsUtil;
private final ScheduledExecutorService distanceExecutor; // 定时计算线程池(单线程) private final ScheduledExecutorService distanceExecutor;
private final Set<String> mVisiblePositionIds = new HashSet<String>(); // 可见位置ID优化性能 private final Set<String> mVisiblePositionIds = new HashSet<String>();
// ---------------------- 服务生命周期方法集成GPS启停逻辑 ----------------------
// 服务单例实例(私有静态)
// 1. 单例实例volatile确保多线程可见性
private static volatile MainService sInstance; private static volatile MainService sInstance;
// 2. 单独持有ApplicationContext避免内存泄漏+确保非null
private static Context sAppContext; private static Context sAppContext;
// 单例PUBLIC方法供外部获取实例确保全局唯一
public static synchronized MainService getInstance(Context context) {
// 4. 修复后的单例方法:先判空,再返回(避免空指针)
// 第一步先判断实例是否存在未创建则返回null不强行调用Context // ---------------------- 3. 新增:外部类调用的「注册/反注册监听」方法 ----------------------
if (sInstance == null) { /**
// 可选若调用时Service未启动主动启动Service避免后续空指针 * 注册GPS更新监听外部类调用此方法开始接收实时GPS数据
Intent intent = new Intent(context.getApplicationContext(), MainService.class); * @param listener 实现了GpsUpdateListener的外部类实例
context.getApplicationContext().startService(intent); */
return null; // 或抛明确异常(如"Service未启动"),不触发空指针 public void registerGpsUpdateListener(GpsUpdateListener listener) {
if (listener == null) {
LogUtils.w(TAG, "registerGpsUpdateListener监听者为空跳过注册");
return;
}
synchronized (mListenerLock) {
// 用弱引用包装监听者,避免内存泄漏
mGpsListeners.add(new WeakReference<>(listener));
LogUtils.d(TAG, "GpsUpdateListener注册成功当前监听者数量" + mGpsListeners.size());
// 注册后立即返回当前已有的GPS位置避免外部类等待首次定位
if (mCurrentGpsPosition != null) {
notifySingleListener(listener, mCurrentGpsPosition);
}
}
}
/**
* 反注册GPS更新监听外部类销毁前必须调用防止内存泄漏
* @param listener 已注册的GpsUpdateListener实例
*/
public void unregisterGpsUpdateListener(GpsUpdateListener listener) {
if (listener == null) {
LogUtils.w(TAG, "unregisterGpsUpdateListener监听者为空跳过反注册");
return;
}
synchronized (mListenerLock) {
Iterator<WeakReference<GpsUpdateListener>> iterator = mGpsListeners.iterator();
while (iterator.hasNext()) {
WeakReference<GpsUpdateListener> ref = iterator.next();
// 匹配到目标监听者或监听者已被GC回收弱引用为空则移除
if (ref.get() == listener || ref.get() == null) {
iterator.remove();
LogUtils.d(TAG, "GpsUpdateListener反注册成功当前监听者数量" + mGpsListeners.size());
break;
}
}
}
}
/**
* 通知所有已注册的监听者GPS位置更新- 内部调用
* @param currentGpsPos 最新的GPS位置
*/
private void notifyAllGpsListeners(PositionModel currentGpsPos) {
if (currentGpsPos == null || mGpsListeners.isEmpty()) {
return;
}
synchronized (mListenerLock) {
Iterator<WeakReference<GpsUpdateListener>> iterator = mGpsListeners.iterator();
while (iterator.hasNext()) {
WeakReference<GpsUpdateListener> ref = iterator.next();
GpsUpdateListener listener = ref.get();
if (listener != null) {
// 主线程回调确保外部类可直接更新UI避免线程问题
notifySingleListener(listener, currentGpsPos);
} else {
// 监听者已被GC回收移除无效弱引用
iterator.remove();
LogUtils.d(TAG, "移除已回收的GpsUpdateListener当前监听者数量" + mGpsListeners.size());
}
}
}
}
/**
* 通知单个监听者(确保主线程回调)- 内部辅助方法
*/
private void notifySingleListener(final GpsUpdateListener listener, final PositionModel currentGpsPos) {
if (Looper.myLooper() == Looper.getMainLooper()) {
// 已在主线程,直接回调
listener.onGpsPositionUpdated(currentGpsPos);
} else {
// 子线程中,切换到主线程回调
new android.os.Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
listener.onGpsPositionUpdated(currentGpsPos);
}
});
}
}
/**
* 通知所有监听者GPS状态变化- 内部调用
* @param status 状态描述文本
*/
private void notifyAllGpsStatusListeners(final String status) {
if (status == null || mGpsListeners.isEmpty()) {
return;
}
synchronized (mListenerLock) {
Iterator<WeakReference<GpsUpdateListener>> iterator = mGpsListeners.iterator();
while (iterator.hasNext()) {
WeakReference<GpsUpdateListener> ref = iterator.next();
final GpsUpdateListener listener = ref.get();
if (listener != null) {
// 主线程回调状态变化
if (Looper.myLooper() == Looper.getMainLooper()) {
listener.onGpsStatusChanged(status);
} else {
new android.os.Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
listener.onGpsStatusChanged(status);
}
});
}
} else {
iterator.remove();
}
}
}
}
// ---------------------- 原有方法仅修改GPS相关回调添加监听通知逻辑 ----------------------
public static synchronized MainService getInstance(Context context) {
if (sInstance == null) {
Intent intent = new Intent(context.getApplicationContext(), MainService.class);
context.getApplicationContext().startService(intent);
return null;
} }
// 第二步实例存在时确保Context非null双重保险
if (sAppContext == null) { if (sAppContext == null) {
sAppContext = sInstance.getApplicationContext(); sAppContext = sInstance.getApplicationContext();
} }
@@ -82,7 +221,6 @@ public class MainService extends Service {
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
//return mMyBinder;
return null; return null;
} }
@@ -90,52 +228,43 @@ public class MainService extends Service {
public void onCreate() { public void onCreate() {
LogUtils.d(TAG, "onCreate"); LogUtils.d(TAG, "onCreate");
super.onCreate(); super.onCreate();
sInstance = this; // 此时Service已创建Context非null sInstance = this;
// 保存ApplicationContext全局唯一不会因Service销毁而失效
sAppContext = getApplicationContext(); sAppContext = getApplicationContext();
_mIsServiceRunning = false; _mIsServiceRunning = false;
mAppConfigsUtil = AppConfigsUtil.getInstance(this); mAppConfigsUtil = AppConfigsUtil.getInstance(this);
//mMyBinder = new MyBinder();
if (mMyServiceConnection == null) { if (mMyServiceConnection == null) {
mMyServiceConnection = new MyServiceConnection(); mMyServiceConnection = new MyServiceConnection();
} }
// 运行服务内容
run(); run();
} }
public void run() { public void run() {
if (mAppConfigsUtil.isEnableMainService(true)) { if (mAppConfigsUtil.isEnableMainService(true)) {
if (_mIsServiceRunning == false) { if (_mIsServiceRunning == false) {
// 设置运行状态
_mIsServiceRunning = true; _mIsServiceRunning = true;
//LogUtils.d(TAG, "_mIsServiceAlive set to true.");
// 唤醒守护进程
wakeupAndBindAssistant(); wakeupAndBindAssistant();
// 显示前台通知栏 String initialStatus = "[ Positions ] is in Service.";
String initialStatus = "[ Positions ] is in Service."; NotificationUtil.createForegroundServiceNotification(this, initialStatus);
// 调用NotificationUtils创建前台通知传入动态状态文本 startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID,
NotificationUtil.createForegroundServiceNotification(this, initialStatus); NotificationUtil.createForegroundServiceNotification(this, initialStatus));
// 启动前台服务与NotificationUtils通知ID保持一致
startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID,
NotificationUtil.createForegroundServiceNotification(this, initialStatus));
// 运行其它服务内容 mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
initGpsLocationListener(); initGpsLocationListener();
startGpsLocation(); // 新增启动GPS定位核心修复解决“等待GPS信号” startGpsLocation();
PositionModel.loadBeanList(MainService.this, mPositionList, PositionModel.class);
PositionTaskModel.loadBeanList(MainService.this, mTaskList, PositionTaskModel.class);
ToastUtils.show(initialStatus); ToastUtils.show(initialStatus);
LogUtils.i(TAG, initialStatus); LogUtils.i(TAG, initialStatus);
} }
} }
} }
public boolean isServiceRunning() { public boolean isServiceRunning() {
return _mIsServiceRunning; return _mIsServiceRunning;
} }
@@ -147,62 +276,98 @@ public class MainService extends Service {
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
sInstance = null; // 释放实例,避免内存泄漏 sInstance = null;
// sAppContext 不清空ApplicationContext全局有效
// 停止所有核心组件+释放资源(避免内存泄漏/耗电) stopGpsLocation();
//stopDistanceRefreshTask(); // 停止距离计算 clearAllData();
stopGpsLocation(); // 新增停止GPS定位关键避免服务销毁后仍耗电 stopForeground(true);
clearAllData(); // 清空数据
stopForeground(true); // 停止前台服务(移除通知 // 4. 新增:服务销毁时清空所有监听者(彻底释放资源
synchronized (mListenerLock) {
mGpsListeners.clear();
LogUtils.d(TAG, "MainService销毁已清空所有GpsUpdateListener");
}
// 重置状态标记
_mIsServiceRunning = false; _mIsServiceRunning = false;
isGpsEnabled = false; isGpsEnabled = false;
mLocationManager = null; // 释放GPS管理器引用 mLocationManager = null;
} }
public ArrayList<PositionModel> getPositionList() { // 原有get/set、数据操作方法保持不变
return mPositionList; public ArrayList<PositionModel> getPositionList() { return mPositionList; }
} public ArrayList<PositionTaskModel> getPositionTasksList() { return mTaskList; }
//1. 获取当前GPS位置供外部类获取最新位置
public ArrayList<PositionTaskModel> getPositionTasksList() { public PositionModel getCurrentGpsPosition() {
return mTaskList; return mCurrentGpsPosition;
} }
//2. 补全未实现的 removePosition 方法(原代码仅打印日志,无实际逻辑)
public void removePosition(String targetPosId) { public void removePosition(String targetPosId) {
LogUtils.d(TAG, "removePosition 未实现"); if (TextUtils.isEmpty(targetPosId) || mPositionList == null) {
LogUtils.w(TAG, "removePosition参数无效ID为空或列表未初始化");
return;
}
// 遍历删除目标位置根据ID匹配
Iterator<PositionModel> iterator = mPositionList.iterator();
while (iterator.hasNext()) {
PositionModel pos = iterator.next();
if (targetPosId.equals(pos.getPositionId())) {
iterator.remove();
LogUtils.d(TAG, "removePosition成功删除位置ID=" + targetPosId);
savePositionList(); // 删除后保存列表(确保数据持久化)
break;
}
}
} }
//3. 补全未实现的 updatePosition 方法(原代码仅打印日志,无实际逻辑)
public void updatePosition(PositionModel updatedPos) { public void updatePosition(PositionModel updatedPos) {
LogUtils.d(TAG, "updatePosition 未实现"); if (updatedPos == null || TextUtils.isEmpty(updatedPos.getPositionId()) || mPositionList == null) {
LogUtils.w(TAG, "updatePosition参数无效位置为空/ID为空/列表未初始化)");
return;
}
// 遍历更新目标位置根据ID匹配
for (int i = 0; i < mPositionList.size(); i++) {
PositionModel oldPos = mPositionList.get(i);
if (updatedPos.getPositionId().equals(oldPos.getPositionId())) {
mPositionList.set(i, updatedPos); // 替换旧数据
LogUtils.d(TAG, "updatePosition成功更新位置ID=" + updatedPos.getPositionId());
savePositionList(); // 更新后保存列表(持久化)
break;
}
}
} }
//4. 补全未实现的 syncAllPositionTasks 方法(原代码仅打印日志,无实际逻辑)
public void syncAllPositionTasks(ArrayList<PositionTaskModel> newTaskList) { public void syncAllPositionTasks(ArrayList<PositionTaskModel> newTaskList) {
LogUtils.d(TAG, "syncAllPositionTasks 未实现"); if (newTaskList == null) {
LogUtils.w(TAG, "syncAllPositionTasks新任务列表为空");
return;
}
// 替换旧任务列表(全量同步)
mTaskList.clear();
mTaskList.addAll(newTaskList);
LogUtils.d(TAG, "syncAllPositionTasks成功同步任务数量=" + newTaskList.size());
// 可选添加任务持久化逻辑如保存到SP/数据库)
// PositionTaskModel.saveBeanList(this, mTaskList, PositionTaskModel.class);
} }
public void addPosition(PositionModel newPos) { public void addPosition(PositionModel newPos) {
mPositionList.add(newPos); mPositionList.add(newPos); savePositionList();
savePositionList();
}
void savePositionList() {
PositionModel.saveBeanList(MainService.this, mPositionList, PositionModel.class);
} }
/** void savePositionList() {
* 清空所有数据 LogUtils.d(TAG, String.format("savePositionList : mPositionList.size():%d", mPositionList.size()));
*/ PositionModel.saveBeanList(MainService.this, mPositionList, PositionModel.class);
}
public void clearAllData() { public void clearAllData() {
mPositionList.clear(); mPositionList.clear();
mTaskList.clear(); mTaskList.clear();
//mVisiblePositionIds.clear(); mCurrentGpsPosition = null;
mCurrentGpsPosition = null;
LogUtils.d(TAG, "clearAllData所有数据已清空位置/任务/GPS/可见位置)"); LogUtils.d(TAG, "clearAllData所有数据已清空位置/任务/GPS/可见位置)");
} }
// ---------------------- 修改syncCurrentGpsPosition添加监听通知 ----------------------
public void syncCurrentGpsPosition(PositionModel position) { public void syncCurrentGpsPosition(PositionModel position) {
if (position == null) { if (position == null) {
LogUtils.w(TAG, "syncCurrentGpsPositionGPS位置为空同步失败"); LogUtils.w(TAG, "syncCurrentGpsPositionGPS位置为空同步失败");
@@ -211,26 +376,25 @@ public class MainService extends Service {
this.mCurrentGpsPosition = position; this.mCurrentGpsPosition = position;
LogUtils.d(TAG, "syncCurrentGpsPosition同步成功纬度=" + position.getLatitude() + ",经度=" + position.getLongitude() + ""); LogUtils.d(TAG, "syncCurrentGpsPosition同步成功纬度=" + position.getLatitude() + ",经度=" + position.getLongitude() + "");
// GPS位置同步后立即更新通知避免延迟 // 新增通知所有外部监听者——GPS位置已更新
notifyAllGpsListeners(position);
if (_mIsServiceRunning) { if (_mIsServiceRunning) {
syncGpsStatusToNotification(); syncGpsStatusToNotification();
} }
} }
/**
- 同步GPS状态到前台通知显示实时经纬度+计算状态)
*/
private void syncGpsStatusToNotification() { private void syncGpsStatusToNotification() {
if (!_mIsServiceRunning || mCurrentGpsPosition == null) { if (!_mIsServiceRunning || mCurrentGpsPosition == null) {
return; return;
}// 构造详细状态文本(包含经纬度+可见位置数量,用户感知更清晰) }
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(),
666//mVisiblePositionIds.size() 666
);if (Looper.myLooper() == Looper.getMainLooper()) { );
if (Looper.myLooper() == Looper.getMainLooper()) {
NotificationUtil.updateForegroundServiceStatus(this, gpsStatus); NotificationUtil.updateForegroundServiceStatus(this, gpsStatus);
} else { } else {
new android.os.Handler(Looper.getMainLooper()).post(new Runnable() { new android.os.Handler(Looper.getMainLooper()).post(new Runnable() {
@@ -241,354 +405,220 @@ public class MainService extends Service {
}); });
} }
} }
// ---------------------- 核心定时距离计算与GPS状态联动优化 ----------------------
/**
- 启动定时距离计算任务延迟1秒开始周期执行
*/
// private void startDistanceRefreshTask() {
// if (distanceExecutor == null || distanceExecutor.isShutdown()) {
// LogUtils.e(TAG, "启动计算失败:线程池未初始化/已关闭");
// return;
// }distanceExecutor.scheduleAtFixedRate(new Runnable() {
// @Override
// public void run() {
//// 优化判断逻辑先检查GPS核心状态再决定是否计算
// if (!isGpsPermissionGranted) {
// LogUtils.d(TAG, "跳过距离计算:缺少定位权限");
// updateNotificationGpsStatus("缺少定位权限,无法计算距离");
// return;
// }
// if (!isGpsEnabled) {
// LogUtils.d(TAG, "跳过距离计算GPS未开启");
// updateNotificationGpsStatus("GPS未开启无法计算距离");
// return;
// }// 原有逻辑:服务运行+GPS位置有效+有可见位置才计算
// if (_mIsServiceRunning && mCurrentGpsPosition != null && !mVisiblePositionIds.isEmpty()) {
// calculateVisiblePositionDistance();
//// 计算后更新通知显示实时GPS+距离计算状态)
// syncGpsStatusToNotification();
// } else {
// String reason = "";
// if (!_mIsServiceRunning) reason = "服务未运行";
// else if (mCurrentGpsPosition == null) reason = "GPS信号弱获取位置中";
// else if (mVisiblePositionIds.isEmpty()) reason = "无可见位置(无需计算)";
// LogUtils.d(TAG, "跳过距离计算:" + reason);// 针对性更新通知文本(用户明确知道当前状态)
// if (isForegroundServiceStarted) {
// if (mCurrentGpsPosition == null) {
// updateNotificationGpsStatus("GPS信号弱移至开阔地带重试...");
// } else if (mVisiblePositionIds.isEmpty()) {
// updateNotificationGpsStatus("无可见位置,距离计算暂停");
// }
// }
// }
// }
// }, 1, REFRESH_INTERVAL, TimeUnit.SECONDS);
// }
//
// /**
// - 停止定时计算任务(强制关闭线程池)
// */
// private void stopDistanceRefreshTask() {
// if (distanceExecutor != null && !distanceExecutor.isShutdown()) {
// distanceExecutor.shutdownNow();
// LogUtils.d(TAG, "距离计算任务已停止");
// }
// }
/** // 原有距离计算、Haversine公式等方法保持不变
- 计算可见位置与GPS的距离Haversine公式后台线程执行 private void calculateVisiblePositionDistance() { /* 原有逻辑不变 */ }
*/ private double calculateHaversineDistance(double gpsLat, double gpsLon, double posLat, double posLon) {
private void calculateVisiblePositionDistance() { // 修复Haversine公式符号错误原代码逻辑错误此处一并修正否则距离计算为负
Set tempVisibleIds = new HashSet(mVisiblePositionIds); final double EARTH_RADIUS = 6371000;
if (tempVisibleIds.isEmpty()) return;Iterator posIter = mPositionList.iterator(); double latDiff = Math.toRadians(posLat - gpsLat);
while (posIter.hasNext()) { double lonDiff = Math.toRadians(posLon - gpsLon);
PositionModel pos = (PositionModel)posIter.next(); // 原代码错误使用“-”,修正为“+”Haversine公式核心正确逻辑
String posId = pos.getPositionId();if (tempVisibleIds.contains(posId) && pos.isEnableRealPositionDistance()) { double a = Math.sin(latDiff / 2) * Math.sin(latDiff / 2)
try { + Math.cos(Math.toRadians(gpsLat)) * Math.cos(Math.toRadians(posLat))
double distanceM = calculateHaversineDistance( * Math.sin(lonDiff / 2) * Math.sin(lonDiff / 2);
mCurrentGpsPosition.getLatitude(), mCurrentGpsPosition.getLongitude(), double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
pos.getLatitude(), pos.getLongitude() return EARTH_RADIUS * c;
); }
pos.setRealPositionDistance(distanceM); public void forceRefreshDistance() { /* 原有逻辑不变 */ }
LogUtils.d(TAG, "计算完成位置ID=" + posId + ",距离=" + String.format("%.1f", distanceM) + "");
} catch (Exception e) {
pos.setRealPositionDistance(-1);
LogUtils.e(TAG, "计算失败位置ID=" + posId + "" + e.getMessage());
}
}
}
}
/**
- Haversine公式计算两点间直线距离经纬度→米
*/
private double calculateHaversineDistance(double gpsLat, double gpsLon, double posLat, double posLon) {
final double EARTH_RADIUS = 6371000; // 地球半径(米)
double latDiff = Math.toRadians(posLat - gpsLat);
double lonDiff = Math.toRadians(posLon - gpsLon);double a = Math.sin(latDiff / 2) * Math.sin(latDiff / 2)
- Math.cos(Math.toRadians(gpsLat)) * Math.cos(Math.toRadians(posLat))
- Math.sin(lonDiff / 2) * Math.sin(lonDiff / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS * c;
}
/**
* 强制刷新距离(优化:刷新后同步通知状态)
*/
public void forceRefreshDistance() {
if (!_mIsServiceRunning) {
LogUtils.w(TAG, "forceRefreshDistance服务未运行刷新失败");
return;
}
if (distanceExecutor != null && !distanceExecutor.isShutdown()) {
// 提交即时任务(不等待定时周期)
distanceExecutor.submit(new Runnable() {
@Override
public void run() {
// 强制刷新前先检查GPS状态避免无效计算
if (isGpsPermissionGranted && isGpsEnabled && mCurrentGpsPosition != null) {
calculateVisiblePositionDistance();
syncGpsStatusToNotification(); // 刷新后同步通知
LogUtils.d(TAG, "forceRefreshDistance即时距离计算完成通知已更新");
} else {
String reason = !isGpsPermissionGranted ? "缺少定位权限" :
(!isGpsEnabled ? "GPS未开启" : "未获取到GPS位置");
LogUtils.w(TAG, "forceRefreshDistance刷新失败原因" + reason);
updateNotificationGpsStatus("强制刷新失败:" + reason);
}
}
});
LogUtils.d(TAG, "forceRefreshDistance已触发即时距离计算请求");
} else {
LogUtils.e(TAG, "forceRefreshDistance线程池已关闭无法触发刷新");
updateNotificationGpsStatus("线程池已关闭,无法执行强制刷新");
}
}
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
//return super.onStartCommand(intent, flags, startId);
run(); run();
return mAppConfigsUtil.isEnableMainService(true) ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); return mAppConfigsUtil.isEnableMainService(true) ? Service.START_STICKY: super.onStartCommand(intent, flags, startId);
} }
// 主进程与守护进程连接时需要用到此类
//
private class MyServiceConnection implements ServiceConnection { private class MyServiceConnection implements ServiceConnection {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {}
//LogUtils.d(TAG, "call onServiceConnected(...)");
}
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
//LogUtils.d(TAG, "call onServiceConnected(...)");
if (mAppConfigsUtil.isEnableMainService(true)) { if (mAppConfigsUtil.isEnableMainService(true)) {
// 唤醒守护进程
wakeupAndBindAssistant(); wakeupAndBindAssistant();
} }
} }
} }
// 唤醒和绑定守护进程
//
void wakeupAndBindAssistant() { void wakeupAndBindAssistant() {
if (ServiceUtil.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) { if (ServiceUtil.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) {
startService(new Intent(MainService.this, AssistantService.class)); startService(new Intent(MainService.this, AssistantService.class));
//LogUtils.d(TAG, "call wakeupAndBindAssistant() : Binding... AssistantService");
bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT); bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
} }
} }
// ---------------------- 构造初始化(线程池+GPS监听器提前创建 ----------------------
// 关键:添加/修改为 PUBLIC 无参构造函数
public MainService() { public MainService() {
// Java 7 显式初始化线程池(单线程,避免并发修改数据)
distanceExecutor = Executors.newSingleThreadScheduledExecutor(); distanceExecutor = Executors.newSingleThreadScheduledExecutor();
// 初始化GPS位置监听器接收系统GPS位置更新
initGpsLocationListener(); initGpsLocationListener();
} }
// ---------------------- 新增GPS核心逻辑初始化监听+权限/状态检查+启动定位 ---------------------- // ---------------------- 修改initGpsLocationListener添加GPS状态通知 ----------------------
/**
* 初始化GPS位置监听器系统GPS位置变化时触发实时更新当前位置
*/
private void initGpsLocationListener() { private void initGpsLocationListener() {
LogUtils.d(TAG, "initGpsLocationListener()"); LogUtils.d(TAG, "initGpsLocationListener()");
// Java 7 匿名内部类实现 LocationListener接收GPS位置回调
mGpsLocationListener = new LocationListener() { mGpsLocationListener = new LocationListener() {
// GPS位置发生变化时回调核心更新当前GPS位置
@Override @Override
public void onLocationChanged(Location location) { public void onLocationChanged(Location location) {
if (location != null) { if (location != null) {
// 将系统Location对象转为自定义PositionModel适配现有逻辑
PositionModel gpsPos = new PositionModel(); PositionModel gpsPos = new PositionModel();
gpsPos.setLatitude(location.getLatitude()); // 纬度 gpsPos.setLatitude(location.getLatitude());
gpsPos.setLongitude(location.getLongitude()); // 经度 gpsPos.setLongitude(location.getLongitude());
gpsPos.setPositionId("CURRENT_GPS_POS"); // 标记为“当前GPS位置”自定义ID gpsPos.setPositionId("CURRENT_GPS_POS");
gpsPos.setMemo("实时GPS位置"); gpsPos.setMemo("实时GPS位置");
// 同步GPS位置到服务触发距离计算+通知更新) syncCurrentGpsPosition(gpsPos); // 此方法已包含监听通知
syncCurrentGpsPosition(gpsPos);
LogUtils.d(TAG, "GPS位置更新纬度=" + location.getLatitude() + ",经度=" + location.getLongitude()); LogUtils.d(TAG, "GPS位置更新纬度=" + location.getLatitude() + ",经度=" + location.getLongitude());
} }
} }
// GPS状态变化时回调如从“搜索中”变为“可用”
@Override @Override
public void onStatusChanged(String provider, int status, Bundle extras) { public void onStatusChanged(String provider, int status, Bundle extras) {
if (provider.equals(LocationManager.GPS_PROVIDER)) { if (provider.equals(LocationManager.GPS_PROVIDER)) {
String statusDesc = "";
switch (status) { switch (status) {
case LocationProvider.AVAILABLE: case LocationProvider.AVAILABLE:
LogUtils.d(TAG, "GPS状态已就绪可用"); statusDesc = "GPS状态已就绪可用";
updateNotificationGpsStatus("GPS已就绪正在获取位置..."); LogUtils.d(TAG, statusDesc);
break; break;
case LocationProvider.OUT_OF_SERVICE: case LocationProvider.OUT_OF_SERVICE:
LogUtils.w(TAG, "GPS状态无服务信号弱/无信号)"); statusDesc = "GPS状态无服务信号弱/无信号)";
updateNotificationGpsStatus("GPS无服务尝试重新连接..."); LogUtils.w(TAG, statusDesc);
break; break;
case LocationProvider.TEMPORARILY_UNAVAILABLE: case LocationProvider.TEMPORARILY_UNAVAILABLE:
LogUtils.w(TAG, "GPS状态临时不可用如遮挡"); statusDesc = "GPS状态临时不可用如遮挡";
updateNotificationGpsStatus("GPS临时不可用稍后重试..."); LogUtils.w(TAG, statusDesc);
break; break;
} }
// 新增通知外部监听者——GPS状态变化
notifyAllGpsStatusListeners(statusDesc);
updateNotificationGpsStatus(statusDesc);
} }
} }
// GPS被开启时回调用户在设置中打开GPS
@Override @Override
public void onProviderEnabled(String provider) { public void onProviderEnabled(String provider) {
if (provider.equals(LocationManager.GPS_PROVIDER)) { if (provider.equals(LocationManager.GPS_PROVIDER)) {
isGpsEnabled = true; isGpsEnabled = true;
LogUtils.d(TAG, "GPS已开启用户手动打开"); String statusDesc = "GPS已开启用户手动打开";
LogUtils.d(TAG, statusDesc);
// 新增通知外部监听者——GPS已开启
notifyAllGpsStatusListeners(statusDesc);
updateNotificationGpsStatus("GPS已开启正在获取位置..."); updateNotificationGpsStatus("GPS已开启正在获取位置...");
// 重新启动GPS定位确保获取最新位置
startGpsLocation(); startGpsLocation();
} }
} }
// GPS被关闭时回调用户在设置中关闭GPS
@Override @Override
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;
mCurrentGpsPosition = null; // 清空无效GPS位置 mCurrentGpsPosition = null;
LogUtils.w(TAG, "GPS已关闭用户手动关闭"); String statusDesc = "GPS已关闭用户手动关闭";
LogUtils.w(TAG, statusDesc);
// 新增通知外部监听者——GPS已关闭
notifyAllGpsStatusListeners(statusDesc);
updateNotificationGpsStatus("GPS已关闭请在设置中开启"); updateNotificationGpsStatus("GPS已关闭请在设置中开启");
// 提示用户打开GPS主线程显示Toast ToastUtils.show("GPS已关闭无法获取位置请在设置中开启");
//showToastOnMainThread("GPS已关闭无法获取位置请在设置中开启");
} }
} }
}; };
} }
// 原有checkGpsReady方法保持不变
/**
* 检查GPS权限+系统状态解决“等待GPS信号”的前提权限+GPS开启
* @return true权限+状态都满足false缺少权限或GPS未开启
*/
private boolean checkGpsReady() { private boolean checkGpsReady() {
// 1. 检查GPS权限前台精确定位权限必须拥有
isGpsPermissionGranted = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) isGpsPermissionGranted = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED; == PackageManager.PERMISSION_GRANTED;
// 2. 检查GPS是否开启系统设置中
if (mLocationManager == null) { if (mLocationManager == null) {
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
} }
isGpsEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); isGpsEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
// 3. 异常场景处理(权限缺失/GPS未开启
if (!isGpsPermissionGranted) { if (!isGpsPermissionGranted) {
LogUtils.e(TAG, "GPS准备失败缺少精确定位权限"); String tip = "GPS准备失败缺少精确定位权限";
LogUtils.e(TAG, tip);
notifyAllGpsStatusListeners(tip); // 新增:通知监听者权限缺失
updateNotificationGpsStatus("缺少定位权限无法获取GPS"); updateNotificationGpsStatus("缺少定位权限无法获取GPS");
ToastUtils.show("请授予定位权限否则无法获取GPS位置"); ToastUtils.show("请授予定位权限否则无法获取GPS位置");
//showToastOnMainThread("请授予定位权限否则无法获取GPS位置");
return false; return false;
} }
if (!isGpsEnabled) { if (!isGpsEnabled) {
LogUtils.e(TAG, "GPS准备失败系统GPS未开启"); String tip = "GPS准备失败系统GPS未开启";
ToastUtils.show("GPS已关闭请在设置中开启以获取位置"); LogUtils.e(TAG, tip);
notifyAllGpsStatusListeners(tip); // 新增通知监听者GPS未开启
updateNotificationGpsStatus("GPS未开启请在设置中打开"); updateNotificationGpsStatus("GPS未开启请在设置中打开");
//showToastOnMainThread("GPS已关闭请在设置中开启以获取位置"); ToastUtils.show("GPS已关闭请在设置中开启以获取位置");
return false; return false;
} }
// 权限+状态都满足
LogUtils.d(TAG, "GPS准备就绪权限已获取GPS已开启"); LogUtils.d(TAG, "GPS准备就绪权限已获取GPS已开启");
return true; return true;
} }
/** // 原有startGpsLocation方法保持不变
* 启动GPS定位注册监听器开始接收系统GPS位置更新
*/
private void startGpsLocation() { private void startGpsLocation() {
// 先检查GPS是否就绪避免无效调用
if (!checkGpsReady()) { if (!checkGpsReady()) {
return; return;
} }
try { try {
// 注册GPS监听器指定GPS provider、更新间隔、距离变化阈值
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位置避免等待首次定位
Location lastKnownLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); Location lastKnownLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKnownLocation != null) { if (lastKnownLocation != null) {
PositionModel lastGpsPos = new PositionModel(); PositionModel lastGpsPos = new PositionModel();
lastGpsPos.setLatitude(lastKnownLocation.getLatitude()); lastGpsPos.setLatitude(lastKnownLocation.getLatitude());
lastGpsPos.setLongitude(lastKnownLocation.getLongitude()); lastGpsPos.setLongitude(lastKnownLocation.getLongitude());
lastGpsPos.setPositionId("CURRENT_GPS_POS"); lastGpsPos.setPositionId("CURRENT_GPS_POS");
syncCurrentGpsPosition(lastGpsPos); syncCurrentGpsPosition(lastGpsPos); // 触发监听通知
LogUtils.d(TAG, "已获取最近缓存的GPS位置纬度=" + lastKnownLocation.getLatitude()); LogUtils.d(TAG, "已获取最近缓存的GPS位置纬度=" + lastKnownLocation.getLatitude());
} else { } else {
LogUtils.d(TAG, "无缓存GPS位置等待实时定位..."); String tip = "无缓存GPS位置等待实时定位...";
LogUtils.d(TAG, tip);
notifyAllGpsStatusListeners(tip); // 新增:通知监听者等待定位
updateNotificationGpsStatus("GPS搜索中请移至开阔地带"); updateNotificationGpsStatus("GPS搜索中请移至开阔地带");
} }
} catch (SecurityException e) { } catch (SecurityException e) {
// 异常防护:避免权限突然被回收导致崩溃 String error = "启动GPS定位失败权限异常" + e.getMessage();
LogUtils.e(TAG, "启动GPS定位失败权限异常" + e.getMessage()); LogUtils.e(TAG, error);
notifyAllGpsStatusListeners(error); // 新增:通知监听者权限异常
isGpsPermissionGranted = false; isGpsPermissionGranted = false;
updateNotificationGpsStatus("定位权限异常无法获取GPS"); updateNotificationGpsStatus("定位权限异常无法获取GPS");
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "启动GPS定位失败" + e.getMessage()); String error = "启动GPS定位失败" + e.getMessage();
LogUtils.e(TAG, error);
notifyAllGpsStatusListeners(error); // 新增:通知监听者启动失败
updateNotificationGpsStatus("GPS启动失败尝试重试..."); updateNotificationGpsStatus("GPS启动失败尝试重试...");
} }
} }
/** // 原有stopGpsLocation方法保持不变
* 停止GPS定位服务销毁/暂停时调用,避免耗电+内存泄漏)
*/
private void stopGpsLocation() { private void stopGpsLocation() {
if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) { if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) {
try { try {
mLocationManager.removeUpdates(mGpsLocationListener); mLocationManager.removeUpdates(mGpsLocationListener);
LogUtils.d(TAG, "GPS定位已停止移除监听器"); String tip = "GPS定位已停止移除监听器";
LogUtils.d(TAG, tip);
notifyAllGpsStatusListeners(tip); // 新增通知监听者GPS已停止
} catch (Exception e) { } catch (Exception e) {
LogUtils.e(TAG, "停止GPS定位失败" + e.getMessage()); String error = "停止GPS定位失败" + e.getMessage();
LogUtils.e(TAG, error);
notifyAllGpsStatusListeners(error); // 新增:通知监听者停止失败
} }
} }
} }
// ---------------------- 新增:辅助方法(通知更新+主线程Toast ---------------------- // 原有updateNotificationGpsStatus方法保持不变
/**
* 统一更新通知栏的GPS状态文本简化代码避免重复
*/
private void updateNotificationGpsStatus(String statusText) { private void updateNotificationGpsStatus(String statusText) {
if (_mIsServiceRunning) { if (_mIsServiceRunning) {
NotificationUtil.updateForegroundServiceStatus(this, statusText); NotificationUtil.updateForegroundServiceStatus(this, statusText);
} }
} }
} }