diff --git a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java index 94a51c9..296b21b 100644 --- a/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java +++ b/positions/src/main/java/cc/winboll/studio/positions/activities/LocationActivity.java @@ -1,9 +1,10 @@ package cc.winboll.studio.positions.activities; /** - * @Author ZhanGSKen&豆包大模型 - * @Date 2025/09/29 18:22 - * @Describe 位置列表页面(适配MainService GPS接口+规范服务交互+完善生命周期) + * @Author 豆包&ZhanGSKen + * @CreateTime 2025/09/29 18:22:00 + * @EditTime 2026/05/03 15:32:10 + * @Describe 位置列表页面,适配MainService GPS接口、规范服务交互、完善生命周期资源释放 */ import android.app.Activity; import android.content.ComponentName; @@ -16,9 +17,11 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.TextView; import android.widget.Toast; + import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; + import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; import cc.winboll.studio.libappbase.LogUtils; @@ -28,46 +31,36 @@ import cc.winboll.studio.positions.R; import cc.winboll.studio.positions.adapters.PositionAdapter; import cc.winboll.studio.positions.models.PositionModel; import cc.winboll.studio.positions.services.MainService; + import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Locale; import java.util.concurrent.atomic.AtomicBoolean; -/** - * Java 7 语法适配: - * 1. 服务绑定用匿名内部类实现 ServiceConnection - * 2. Adapter 初始化传入 MainService 实例,确保数据来源唯一 - * 3. 所有位置/任务操作通过 MainService 接口执行 - */ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivity { public static final String TAG = "LocationActivity"; - private Toolbar mToolbar; - + // ======================== 全局属性 ======================== + private Toolbar mToolbar; private RecyclerView mRvPosition; private PositionAdapter mPositionAdapter; - // MainService 引用+绑定状态(AtomicBoolean 确保多线程状态可见性) private MainService mMainService; private final AtomicBoolean isServiceBound = new AtomicBoolean(false); - // 标记 Adapter 是否已初始化(避免重复初始化/销毁后初始化) private final AtomicBoolean isAdapterInited = new AtomicBoolean(false); - // ---------------------- 新增:GPS监听核心变量 ---------------------- - private MainService.GpsUpdateListener mGpsUpdateListener; // GPS监听实例 - private PositionModel mCurrentGpsPos; // 缓存当前GPS位置(供页面使用) - // 本地位置缓存(解决服务数据未同步时Adapter空数据问题) + private MainService.GpsUpdateListener mGpsUpdateListener; + private PositionModel mCurrentGpsPos; private final ArrayList mLocalPosCache = new ArrayList(); - - // 服务连接(Java 7 匿名内部类实现,强化状态同步+数据预加载) - private ServiceConnection mServiceConnection = new ServiceConnection() { + // ======================== 服务连接回调 ======================== + private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { - // 1. 安全获取服务实例(避免强转失败+服务未就绪) + LogUtils.d(TAG,"onServiceConnected 执行"); if (!(service instanceof MainService.LocalBinder)) { - LogUtils.e(TAG, "服务绑定失败:Binder类型不匹配(非MainService.LocalBinder)"); + LogUtils.e(TAG, "服务绑定失败:Binder类型不匹配"); isServiceBound.set(false); return; } @@ -75,19 +68,14 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit try { MainService.LocalBinder binder = (MainService.LocalBinder) service; mMainService = binder.getService(); - // 2. 标记服务绑定成功(原子操作,确保多线程可见) isServiceBound.set(true); - LogUtils.d(TAG, "MainService绑定成功,开始同步数据+初始化Adapter"); + LogUtils.d(TAG,"MainService 绑定成功"); - // 3. 同步服务数据到本地缓存(核心:先同步数据,再初始化Adapter) syncDataFromMainService(); - // 4. 注册GPS监听(确保监听在Adapter前初始化,数据不丢失) registerGpsListener(); - // 5. 初始化Adapter(传入本地缓存+服务实例,数据非空) initPositionAdapter(); - } catch (Exception e) { - LogUtils.d(TAG, "服务绑定后初始化失败:" + e.getMessage()); + LogUtils.e(TAG,"服务绑定初始化异常:" + e.getMessage()); isServiceBound.set(false); mMainService = null; showToast("服务初始化失败,无法加载数据"); @@ -96,15 +84,14 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit @Override public void onServiceDisconnected(ComponentName name) { - LogUtils.w(TAG, "MainService断开连接,清空引用+标记状态"); - // 1. 清空服务引用+标记绑定状态 + LogUtils.w(TAG,"MainService 断开连接"); mMainService = null; isServiceBound.set(false); - // 2. 标记Adapter未初始化(下次绑定需重新初始化) isAdapterInited.set(false); } }; + // ======================== 接口实现 ======================== @Override public Activity getActivity() { return this; @@ -115,283 +102,281 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit return TAG; } + // ======================== 生命周期 ======================== @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + LogUtils.d(TAG,"onCreate 进入"); setContentView(R.layout.activity_location); - mToolbar = findViewById(R.id.toolbar); + mToolbar = findViewById(R.id.toolbar); setSupportActionBar(mToolbar); - mToolbar.setSubtitle(getTag()); + mToolbar.setSubtitle(getTag()); mToolbar.setTitleTextAppearance(this, R.style.Toolbar_TitleText); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - LogUtils.d(TAG, "【导航栏】点击返回"); + LogUtils.d(TAG,"点击导航返回按钮"); startActivity(new Intent(LocationActivity.this, MainActivity.class)); finish(); } }); - // 1. 初始化视图(优先执行,避免Adapter初始化时视图为空) initView(); - // 2. 初始化GPS监听(提前创建,避免绑定服务后空指针) initGpsUpdateListener(); - // 3. 绑定MainService(最后执行,确保视图/监听已就绪) bindMainService(); } - /** - * 初始化视图(RecyclerView)- 确保视图先于Adapter初始化 - */ + @Override + protected void onResume() { + super.onResume(); + LogUtils.d(TAG,"onResume 进入"); + if (isServiceBound.get() && mMainService != null && !isAdapterInited.get()) { + syncDataFromMainService(); + initPositionAdapter(); + } else if (isServiceBound.get() && mMainService != null + && isAdapterInited.get() && mPositionAdapter != null) { + syncDataFromMainService(); + mPositionAdapter.notifyDataSetChanged(); + } + } + + @Override + protected void onPause() { + super.onPause(); + LogUtils.d(TAG,"onPause 页面进入后台"); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LogUtils.d(TAG,"onDestroy 开始释放资源"); + + unregisterGpsListener(); + + if (mPositionAdapter != null) { + mPositionAdapter.release(); + mPositionAdapter = null; + LogUtils.d(TAG,"Adapter资源已释放"); + } + + if (isServiceBound.get()) { + try { + unbindService(mServiceConnection); + LogUtils.d(TAG,"MainService 解绑完成"); + } catch (IllegalArgumentException e) { + LogUtils.e(TAG,"解绑异常:服务已提前解绑"); + } + isServiceBound.set(false); + mMainService = null; + } + + synchronized (mLocalPosCache) { + mLocalPosCache.clear(); + } + mCurrentGpsPos = null; + mGpsUpdateListener = null; + isAdapterInited.set(false); + LogUtils.d(TAG,"全部资源释放完毕"); + } + + // ======================== 视图初始化 ======================== private void initView() { - mRvPosition = (RecyclerView) findViewById(R.id.rv_position_list); - // 1. 显式设置布局管理器(避免Adapter设置时无布局管理器崩溃) + LogUtils.d(TAG,"initView 执行视图初始化"); + mRvPosition = findViewById(R.id.rv_position_list); LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); mRvPosition.setLayoutManager(layoutManager); - // 2. 初始化本地缓存(避免首次加载时缓存为空) mLocalPosCache.clear(); - LogUtils.d(TAG, "视图初始化完成(布局管理器+本地缓存已就绪)"); } - /** - * 绑定MainService(Java 7 显式Intent,强化绑定安全性) - */ + // ======================== 服务绑定 ======================== private void bindMainService() { - // 1. 避免重复绑定(快速重建Activity时防止多绑定) + LogUtils.d(TAG,"bindMainService 发起服务绑定"); if (isServiceBound.get()) { - LogUtils.w(TAG, "无需重复绑定:MainService已绑定"); + LogUtils.w(TAG,"服务已绑定,无需重复操作"); return; } - Intent serviceIntent = new Intent(this, MainService.class); - // 2. 绑定服务(BIND_AUTO_CREATE:服务不存在时自动创建,增加绑定成功率) boolean bindSuccess = bindService(serviceIntent, mServiceConnection, BIND_AUTO_CREATE); if (!bindSuccess) { - LogUtils.e(TAG, "发起MainService绑定请求失败(服务未找到/系统限制)"); + LogUtils.e(TAG,"发起服务绑定请求失败"); showToast("服务绑定失败,无法加载位置数据"); - } else { - LogUtils.d(TAG, "MainService绑定请求已发起"); } } - /** - * 从MainService同步数据到本地缓存(核心解决Adapter空数据问题) - * 作用:1. 服务数据优先同步到本地,Adapter基于本地缓存初始化 - * 2. 避免服务数据更新时直接操作Adapter,通过缓存中转 - */ + // ======================== 数据同步 ======================== private void syncDataFromMainService() { - // 1. 安全校验(服务未绑定/服务空,用本地缓存兜底) + LogUtils.d(TAG,"syncDataFromMainService 开始同步服务数据"); if (!isServiceBound.get() || mMainService == null) { - LogUtils.w(TAG, "同步数据:服务未就绪,使用本地缓存(当前缓存量=" + mLocalPosCache.size() + ")"); + LogUtils.w(TAG,"服务未就绪,使用本地缓存兜底"); return; } - try { - // 2. 从服务获取最新位置数据(同步操作,确保数据拿到后再返回) ArrayList servicePosList = mMainService.getPositionList(); - // 3. 同步到本地缓存(清空旧数据+添加新数据,避免重复) - synchronized (mLocalPosCache) { // 加锁避免多线程操作缓存冲突 + synchronized (mLocalPosCache) { mLocalPosCache.clear(); if (servicePosList != null && !servicePosList.isEmpty()) { mLocalPosCache.addAll(servicePosList); } } - LogUtils.d(TAG, "数据同步完成:服务位置数=" + (servicePosList == null ? 0 : servicePosList.size()) - + ",本地缓存数=" + mLocalPosCache.size()); - + LogUtils.d(TAG,"数据同步完成,本地缓存数量:" + mLocalPosCache.size()); } catch (Exception e) { - LogUtils.d(TAG, "同步服务数据失败:" + e.getMessage()); - // 异常时保留本地缓存,避免Adapter无数据 - LogUtils.w(TAG, "同步失败,使用本地缓存兜底(缓存量=" + mLocalPosCache.size() + ")"); + LogUtils.e(TAG,"同步服务数据异常:" + e.getMessage()); } } - /** - * 初始化PositionAdapter(核心优化:基于本地缓存初始化,避免空数据) - */ + // ======================== Adapter初始化 ======================== private void initPositionAdapter() { - // 1. 多重安全校验(避免销毁后初始化/重复初始化/依赖未就绪) - if (isAdapterInited.get() || !isServiceBound.get() || mMainService == null || mRvPosition == null) { - LogUtils.w(TAG, "Adapter初始化跳过:" - + "已初始化=" + isAdapterInited.get() - + ",服务绑定=" + isServiceBound.get() - + ",视图就绪=" + (mRvPosition != null)); + LogUtils.d(TAG,"initPositionAdapter 开始初始化Adapter"); + if (isAdapterInited.get() || !isServiceBound.get() + || mMainService == null || mRvPosition == null) { + LogUtils.w(TAG,"Adapter条件不满足,跳过初始化"); return; } try { - // 2. 基于本地缓存初始化Adapter(缓存已同步服务数据,非空) mPositionAdapter = new PositionAdapter(this, mLocalPosCache, mMainService); - - // 3. 设置删除回调(删除时同步服务+本地缓存+Adapter) mPositionAdapter.setOnDeleteClickListener(new PositionAdapter.OnDeleteClickListener() { @Override public void onDeleteClick(final int position) { - YesNoAlertDialog.show(LocationActivity.this, "删除位置提示", "是否删除此项锚点位置?", new YesNoAlertDialog.OnDialogResultListener(){ - - @Override - public void onNo() { - } - - @Override - public void onYes() { - // 安全校验(索引有效+服务绑定+缓存非空) - if (position < 0 || position >= mLocalPosCache.size() || !isServiceBound.get() || mMainService == null) { - LogUtils.w(TAG, "删除位置失败:索引无效/服务未就绪(索引=" + position + ",缓存量=" + mLocalPosCache.size() + ")"); - return; - } - - PositionModel deletePos = mLocalPosCache.get(position); - if (deletePos != null && !deletePos.getPositionId().isEmpty()) { - // 步骤1:调用服务删除(确保服务数据一致性) - mMainService.removePosition(deletePos.getPositionId()); - // 步骤2:删除本地缓存(确保缓存与服务同步) - synchronized (mLocalPosCache) { - mLocalPosCache.remove(position); - } - // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据) - mPositionAdapter.notifyItemRemoved(position); - showToast("删除位置成功:" + deletePos.getMemo()); - LogUtils.d(TAG, "删除位置完成:ID=" + deletePos.getPositionId() + "(服务+缓存已同步)"); - } - } - }); + YesNoAlertDialog.show(LocationActivity.this, "删除位置提示", + "是否删除此项锚点位置?", new YesNoAlertDialog.OnDialogResultListener() { + @Override + public void onNo() {} + @Override + public void onYes() { + LogUtils.d(TAG,"执行删除操作,索引:" + position); + if (position < 0 || position >= mLocalPosCache.size() + || !isServiceBound.get() || mMainService == null) { + LogUtils.w(TAG,"删除参数非法,操作终止"); + return; + } + PositionModel deletePos = mLocalPosCache.get(position); + if (deletePos != null && !deletePos.getPositionId().isEmpty()) { + mMainService.removePosition(deletePos.getPositionId()); + synchronized (mLocalPosCache) { + mLocalPosCache.remove(position); + } + mPositionAdapter.notifyItemRemoved(position); + showToast("删除位置成功:" + deletePos.getMemo()); + } + } + }); } }); - // 4. 设置保存回调(保存时同步服务+本地缓存+Adapter) mPositionAdapter.setOnSavePositionClickListener(new PositionAdapter.OnSavePositionClickListener() { @Override public void onSavePositionClick(int position, PositionModel updatedPos) { - // 安全校验(索引有效+服务绑定+数据非空) - if (!isServiceBound.get() || mMainService == null - || position < 0 || position >= mLocalPosCache.size() || updatedPos == null) { - LogUtils.w(TAG, "保存位置失败:服务未就绪/索引无效/数据空"); + LogUtils.d(TAG,"执行保存修改,索引:" + position); + if (!isServiceBound.get() || mMainService == null + || position < 0 || position >= mLocalPosCache.size() || updatedPos == null) { + LogUtils.w(TAG,"保存参数非法,操作终止"); showToast("服务未就绪,保存失败"); return; } - - // 步骤1:调用服务更新(确保服务数据一致性) mMainService.updatePosition(updatedPos); - // 步骤2:更新本地缓存(确保缓存与服务同步) synchronized (mLocalPosCache) { mLocalPosCache.set(position, updatedPos); } - // 步骤3:通知Adapter刷新(基于缓存操作,避免空数据) mPositionAdapter.notifyItemChanged(position); showToast("保存位置成功:" + updatedPos.getMemo()); - LogUtils.d(TAG, "保存位置完成:ID=" + updatedPos.getPositionId() + "(服务+缓存已同步)"); } }); - // 5. 设置Adapter到RecyclerView(最后一步,确保Adapter已配置完成) mRvPosition.setAdapter(mPositionAdapter); - // 6. 标记Adapter已初始化(避免重复初始化) isAdapterInited.set(true); - LogUtils.d(TAG, "PositionAdapter初始化完成(基于本地缓存,数据量=" + mLocalPosCache.size() + ")"); - + LogUtils.d(TAG,"PositionAdapter 初始化完成"); } catch (Exception e) { - LogUtils.d(TAG, "Adapter初始化失败:" + e.getMessage()); + LogUtils.e(TAG,"Adapter初始化失败:" + e.getMessage()); isAdapterInited.set(false); mPositionAdapter = null; showToast("位置列表初始化失败,请重试"); } } - /** - * 显示Toast(Java 7 显式Toast.makeText,避免空Context) - */ + // ======================== 工具Toast ======================== private void showToast(String content) { - if (isFinishing() || isDestroyed()) { // 避免Activity销毁后弹Toast崩溃 - LogUtils.w(TAG, "Activity已销毁,跳过Toast:" + content); + if (isFinishing() || isDestroyed()) { + LogUtils.w(TAG,"Activity已销毁,取消Toast弹窗"); return; } Toast.makeText(this, content, Toast.LENGTH_SHORT).show(); } - // ---------------------- 页面交互(新增位置逻辑保留,适配GPS数据) ---------------------- - /** - * 新增位置(调用服务addPosition(),可选:用当前GPS位置初始化新位置) - */ + // ======================== 新增位置 ======================== public void addNewPosition(View view) { - // 1. 隐藏软键盘(避免软键盘遮挡操作) + LogUtils.d(TAG,"addNewPosition 触发新增位置"); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (imm != null && getCurrentFocus() != null) { imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); } - // 2. 安全校验(服务未绑定,不允许新增) if (!isServiceBound.get() || mMainService == null) { - LogUtils.w(TAG, "新增位置失败:MainService未绑定"); + LogUtils.w(TAG,"服务未绑定,无法新增位置"); showToast("服务未就绪,无法新增位置"); return; } - // 3. 创建新位置模型(优化:优先用当前GPS位置初始化,无则用默认值) PositionModel newPos = new PositionModel(); - newPos.setPositionId(PositionModel.genPositionId()); // 生成唯一ID(需PositionModel实现) + newPos.setPositionId(PositionModel.genPositionId()); if (mCurrentGpsPos != null) { newPos.setLongitude(mCurrentGpsPos.getLongitude()); newPos.setLatitude(mCurrentGpsPos.getLatitude()); newPos.setMemo("当前GPS位置(可编辑)"); } else { - newPos.setLongitude(116.404267); // 北京经度(默认值) - newPos.setLatitude(39.915119); // 北京纬度(默认值) + newPos.setLongitude(116.404267); + newPos.setLatitude(39.915119); newPos.setMemo("默认位置(可编辑备注)"); } - newPos.setIsSimpleView(true); // 默认简单视图 - newPos.setIsEnableRealPositionDistance(true); // 启用距离计算(依赖GPS) + newPos.setIsSimpleView(true); + newPos.setIsEnableRealPositionDistance(true); - // 4. 调用服务新增+同步本地缓存(确保缓存与服务一致) mMainService.addPosition(newPos); synchronized (mLocalPosCache) { mLocalPosCache.add(newPos); } - LogUtils.d(TAG, "通过服务新增位置:ID=" + newPos.getPositionId() + ",纬度=" + newPos.getLatitude() + "(缓存已同步)"); + LogUtils.d(TAG,"新增位置成功,ID:" + newPos.getPositionId()); - // 5. 刷新Adapter(基于缓存操作,确保数据立即显示) if (isAdapterInited.get() && mPositionAdapter != null) { mPositionAdapter.notifyItemInserted(mLocalPosCache.size() - 1); } showToast("新增位置成功(已启用GPS距离计算)"); } - // ---------------------- 新增:GPS监听初始化+注册/反注册(核心适配逻辑) ---------------------- - /** - * 初始化GPS监听:实现MainService.GpsUpdateListener,接收实时GPS数据 - */ + // ======================== GPS监听管理 ======================== private void initGpsUpdateListener() { - LogUtils.d(TAG, "initGpsUpdateListener()"); + LogUtils.d(TAG,"initGpsUpdateListener 初始化GPS监听"); mGpsUpdateListener = new MainService.GpsUpdateListener() { @Override public void onGpsPositionUpdated(PositionModel currentGpsPos) { if (currentGpsPos == null || isFinishing() || isDestroyed()) { - LogUtils.w(TAG, "GPS位置更新:数据为空或Activity已销毁"); return; } - // 缓存当前GPS位置(供页面其他逻辑使用) mCurrentGpsPos = currentGpsPos; - LogUtils.d(TAG, String.format("收到GPS更新:纬度=%.4f,经度=%.4f" - , currentGpsPos.getLatitude(), currentGpsPos.getLongitude())); - // 安全更新UI(避免Activity销毁后操作视图崩溃) - ((TextView)findViewById(R.id.tv_latitude)).setText(String.format("当前纬度:%f", currentGpsPos.getLatitude())); - ((TextView)findViewById(R.id.tv_longitude)).setText(String.format("当前经度:%f", currentGpsPos.getLongitude())); - // 设置格式化后的时间字符串 - long currentTime = System.currentTimeMillis(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()); - String timeStr = sdf.format(new Date(currentTime)); - // 设置当前时间 + LogUtils.d(TAG,"GPS更新 纬度:" + currentGpsPos.getLatitude() + + " 经度:" + currentGpsPos.getLongitude()); + + ((TextView)findViewById(R.id.tv_latitude)) + .setText(String.format("当前纬度:%f", currentGpsPos.getLatitude())); + ((TextView)findViewById(R.id.tv_longitude)) + .setText(String.format("当前经度:%f", currentGpsPos.getLongitude())); + + long currentTime = System.currentTimeMillis(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()); + String timeStr = sdf.format(new Date(currentTime)); ((TextView)findViewById(R.id.tv_timenow)).setText("现在时间:" + timeStr); } @Override public void onGpsStatusChanged(String status) { - if (status == null || isFinishing() || isDestroyed()) return; - LogUtils.d(TAG, "GPS状态变化:" + status); + if (status == null || isFinishing() || isDestroyed()){ + return; + } + LogUtils.d(TAG,"GPS状态变更:" + status); if (status.contains("未开启") || status.contains("权限") || status.contains("失败")) { ToastUtils.show("GPS提示:" + status); } @@ -399,111 +384,29 @@ public class LocationActivity extends WinBoLLActivity implements IWinBoLLActivit }; } - /** - * 注册GPS监听:调用MainService的PUBLIC方法,绑定监听 - */ private void registerGpsListener() { - // 安全校验(避免Activity销毁/服务未绑定/监听为空时注册) - if (isFinishing() || isDestroyed() || !isServiceBound.get() || mMainService == null || mGpsUpdateListener == null) { - LogUtils.w(TAG, "GPS监听注册跳过:Activity状态异常/依赖未就绪"); + LogUtils.d(TAG,"registerGpsListener 注册GPS监听"); + if (isFinishing() || isDestroyed() || !isServiceBound.get() + || mMainService == null || mGpsUpdateListener == null) { return; } try { mMainService.registerGpsUpdateListener(mGpsUpdateListener); - LogUtils.d(TAG, "GPS监听已注册"); } catch (Exception e) { - LogUtils.d(TAG, "GPS监听注册失败:" + e.getMessage()); + LogUtils.e(TAG,"GPS监听注册失败:" + e.getMessage()); } } - /** - * 反注册GPS监听:调用MainService的PUBLIC方法,解绑监听(核心防内存泄漏+数据异常) - */ private void unregisterGpsListener() { - // 避免Activity销毁后调用服务方法(防止空指针/服务已解绑) + LogUtils.d(TAG,"unregisterGpsListener 反注册GPS监听"); if (mMainService == null || mGpsUpdateListener == null) { - LogUtils.w(TAG, "GPS监听反注册跳过:服务/监听未初始化"); return; } try { mMainService.unregisterGpsUpdateListener(mGpsUpdateListener); - LogUtils.d(TAG, "GPS监听已反注册"); } catch (Exception e) { - LogUtils.d(TAG, "GPS监听反注册失败:" + e.getMessage()); + LogUtils.e(TAG,"GPS监听反注册失败:" + e.getMessage()); } } - - /** - * 页面可见时同步数据(解决快速切回时数据未更新问题) - * 场景:快速关闭再打开Activity,服务已绑定但数据未重新同步 - */ - @Override - protected void onResume() { - super.onResume(); - // 1. 服务已绑定但Adapter未初始化:重新同步数据+初始化Adapter - if (isServiceBound.get() && mMainService != null && !isAdapterInited.get()) { - LogUtils.d(TAG, "onResume:服务已绑定但Adapter未初始化,重新同步数据"); - syncDataFromMainService(); - initPositionAdapter(); - } else if (isServiceBound.get() && mMainService != null && isAdapterInited.get() && mPositionAdapter != null) { - syncDataFromMainService(); - mPositionAdapter.notifyDataSetChanged(); - LogUtils.d(TAG, "onResume:刷新位置数据(与服务同步)"); - } - } - - /** - * 页面不可见时暂停操作(避免后台操作导致数据异常) - */ - @Override - protected void onPause() { - super.onPause(); - // 避免后台时仍执行UI刷新(如GPS更新触发的视图操作) - LogUtils.d(TAG, "onPause:页面不可见,暂停UI相关操作"); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - LogUtils.d(TAG, "onDestroy:开始释放资源"); - - // 1. 反注册GPS监听(优先执行,避免服务持有Activity引用导致内存泄漏) - unregisterGpsListener(); - - // 2. 释放Adapter资源(反注册可能的监听,避免内存泄漏) - if (mPositionAdapter != null) { - mPositionAdapter.release(); - mPositionAdapter = null; // 清空引用,帮助GC回收 - LogUtils.d(TAG, "Adapter资源已释放"); - } - - // 3. 解绑MainService(最后执行,确保其他资源已释放) - if (isServiceBound.get()) { - try { - unbindService(mServiceConnection); - LogUtils.d(TAG, "MainService解绑完成"); - } catch (IllegalArgumentException e) { - // 捕获“服务未绑定”异常(快速开关时可能出现,避免崩溃) - LogUtils.d(TAG, "解绑MainService失败:服务未绑定(可能已提前解绑)"); - } - // 重置绑定状态+服务引用 - isServiceBound.set(false); - mMainService = null; - } - - // 4. 清空本地缓存+GPS引用(帮助GC回收) - synchronized (mLocalPosCache) { - mLocalPosCache.clear(); - } - mCurrentGpsPos = null; - mGpsUpdateListener = null; - isAdapterInited.set(false); - LogUtils.d(TAG, "所有资源释放完成(onDestroy执行结束)"); - } - - // ---------------------- 移除重复定义:LocalBinder 统一在 MainService 中定义 ---------------------- - // 说明:原LocationActivity中的LocalBinder是重复定义(MainService已实现),会导致类型强转失败 - // 此处删除该类,确保Activity绑定服务时强转的是MainService中的LocalBinder } -