修复位置列表项中任务列表控件的资源释放后,未再次加载任务列表的问题。
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Tue Oct 07 02:42:31 HKT 2025
|
#Wed Oct 08 13:15:15 GMT 2025
|
||||||
stageCount=11
|
stageCount=11
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.0
|
baseVersion=15.0
|
||||||
publishVersion=15.0.10
|
publishVersion=15.0.10
|
||||||
buildCount=0
|
buildCount=4
|
||||||
baseBetaVersion=15.0.11
|
baseBetaVersion=15.0.11
|
||||||
|
|||||||
@@ -3,9 +3,19 @@ package cc.winboll.studio.positions.adapters;
|
|||||||
/**
|
/**
|
||||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||||
* @Date 2025/09/29 20:25
|
* @Date 2025/09/29 20:25
|
||||||
* @Describe 位置数据适配器(集成PositionTaskListView,移除未定义onDestroy,Java 7语法适配)
|
* @Describe 位置数据适配器(修复视图复用资源加载,支持滚动后重新绑定数据,Java 7语法适配)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java 7 语法严格适配 + 视图复用资源加载修复:
|
||||||
|
* 1. 保留无Lambda/弱引用/线程安全集合等原有适配
|
||||||
|
* 2. 修复核心问题:移除 onViewDetachedFromWindow 中关键资源释放,改为 onBind 时重新绑定
|
||||||
|
* 3. 强化资源复用:任务视图/距离控件在复用后自动从服务同步最新数据,确保滚动后数据不丢失
|
||||||
|
* 4. 优化缓存逻辑:仅清理脱离屏幕且无效的控件缓存,有效控件保留引用供局部更新(如距离)
|
||||||
*/
|
*/
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -14,30 +24,18 @@ import android.widget.Button;
|
|||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.positions.R;
|
import cc.winboll.studio.positions.R;
|
||||||
import cc.winboll.studio.positions.models.PositionModel;
|
import cc.winboll.studio.positions.models.PositionModel;
|
||||||
import cc.winboll.studio.positions.models.PositionTaskModel;
|
import cc.winboll.studio.positions.models.PositionTaskModel;
|
||||||
import cc.winboll.studio.positions.services.MainService;
|
import cc.winboll.studio.positions.services.MainService;
|
||||||
import cc.winboll.studio.positions.views.PositionTaskListView;
|
import cc.winboll.studio.positions.views.PositionTaskListView;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.ConcurrentModificationException;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
|
||||||
* Java 7 语法严格适配:
|
|
||||||
* 1. 无Lambda/方法引用,全匿名内部类实现回调
|
|
||||||
* 2. 移除未定义的 taskView.onDestroy(),改用「清空数据+解绑监听」替代资源释放
|
|
||||||
* 3. 弱引用管理服务/控件,杜绝内存泄漏
|
|
||||||
* 4. PositionTaskListView 初始化/同步/资源释放全链路适配
|
|
||||||
*/
|
|
||||||
public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements MainService.TaskUpdateListener {
|
public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements MainService.TaskUpdateListener {
|
||||||
public static final String TAG = "PositionAdapter";
|
public static final String TAG = "PositionAdapter";
|
||||||
|
|
||||||
@@ -57,10 +55,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final ArrayList<PositionModel> mCachedPositionList; // 位置缓存(与MainService同步)
|
private final ArrayList<PositionModel> mCachedPositionList; // 位置缓存(与MainService同步)
|
||||||
private final WeakReference<MainService> mMainServiceRef; // 弱引用MainService,防内存泄漏
|
private final WeakReference<MainService> mMainServiceRef; // 弱引用MainService,防内存泄漏
|
||||||
// 控件缓存:位置ID → 对应任务列表视图(分别缓存简单/编辑模式,避免引用混淆)
|
// 控件缓存:位置ID → 对应任务列表视图(分别缓存简单/编辑模式,支持复用后快速同步)
|
||||||
private final ConcurrentHashMap<String, PositionTaskListView> mSimpleTaskViewMap;
|
private final ConcurrentHashMap<String, PositionTaskListView> mSimpleTaskViewMap;
|
||||||
private final ConcurrentHashMap<String, PositionTaskListView> mEditTaskViewMap;
|
private final ConcurrentHashMap<String, PositionTaskListView> mEditTaskViewMap;
|
||||||
// 距离控件缓存(用于局部更新距离UI)
|
// 距离控件缓存(用于局部更新距离UI,保留有效引用避免复用后更新失效)
|
||||||
private final ConcurrentHashMap<String, TextView> mPosDistanceViewMap;
|
private final ConcurrentHashMap<String, TextView> mPosDistanceViewMap;
|
||||||
|
|
||||||
// 回调接口(仅处理位置逻辑,任务逻辑通过PositionTaskListView+MainService完成)
|
// 回调接口(仅处理位置逻辑,任务逻辑通过PositionTaskListView+MainService完成)
|
||||||
@@ -81,7 +79,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
public PositionAdapter(Context context, ArrayList<PositionModel> cachedPositionList, MainService mainService) {
|
public PositionAdapter(Context context, ArrayList<PositionModel> cachedPositionList, MainService mainService) {
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
// 容错处理:避免传入null导致空指针
|
// 容错处理:避免传入null导致空指针
|
||||||
this.mCachedPositionList = (cachedPositionList!= null)? cachedPositionList : new ArrayList<PositionModel>();
|
this.mCachedPositionList = (cachedPositionList != null) ? cachedPositionList : new ArrayList<PositionModel>();
|
||||||
// 弱引用MainService:防止Adapter持有服务导致内存泄漏(Java 7 弱引用语法)
|
// 弱引用MainService:防止Adapter持有服务导致内存泄漏(Java 7 弱引用语法)
|
||||||
this.mMainServiceRef = new WeakReference<MainService>(mainService);
|
this.mMainServiceRef = new WeakReference<MainService>(mainService);
|
||||||
// 初始化控件缓存(线程安全集合,适配多线程更新场景)
|
// 初始化控件缓存(线程安全集合,适配多线程更新场景)
|
||||||
@@ -90,7 +88,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
this.mPosDistanceViewMap = new ConcurrentHashMap<String, TextView>();
|
this.mPosDistanceViewMap = new ConcurrentHashMap<String, TextView>();
|
||||||
|
|
||||||
// 注册MainService任务监听:服务任务变化时同步刷新任务列表视图
|
// 注册MainService任务监听:服务任务变化时同步刷新任务列表视图
|
||||||
if (mainService!= null) {
|
if (mainService != null) {
|
||||||
mainService.registerTaskUpdateListener(this);
|
mainService.registerTaskUpdateListener(this);
|
||||||
LogUtils.d(TAG, "已注册MainService任务监听,确保任务数据与服务同步");
|
LogUtils.d(TAG, "已注册MainService任务监听,确保任务数据与服务同步");
|
||||||
} else {
|
} else {
|
||||||
@@ -101,12 +99,12 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// RecyclerView 核心方法(视图类型判断+创建+绑定,集成任务列表视图)
|
// RecyclerView 核心方法(强化视图复用逻辑,复用后自动重新绑定资源)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
PositionModel posModel = getPositionByIndex(position);
|
PositionModel posModel = getPositionByIndex(position);
|
||||||
return (posModel!= null && posModel.isSimpleView())? VIEW_TYPE_SIMPLE : VIEW_TYPE_EDIT;
|
return (posModel != null && posModel.isSimpleView()) ? VIEW_TYPE_SIMPLE : VIEW_TYPE_EDIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,24 +129,26 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
final String posId = posModel.getPositionId();
|
final String posId = posModel.getPositionId();
|
||||||
MainService mainService = mMainServiceRef.get();
|
MainService mainService = mMainServiceRef.get();
|
||||||
|
|
||||||
// 按视图类型绑定数据(简单模式/编辑模式)
|
// 按视图类型绑定数据(简单模式/编辑模式)—— 核心修复:复用后重新绑定所有资源
|
||||||
if (holder instanceof SimpleViewHolder) {
|
if (holder instanceof SimpleViewHolder) {
|
||||||
|
LogUtils.d(TAG, "instanceof SimpleViewHolder(复用/新创建):位置ID=" + posId);
|
||||||
SimpleViewHolder simpleHolder = (SimpleViewHolder) holder;
|
SimpleViewHolder simpleHolder = (SimpleViewHolder) holder;
|
||||||
// 1. 绑定位置基础数据(经纬度/备注/距离)
|
// 1. 重新绑定位置基础数据(经纬度/备注/距离,确保复用后显示最新数据)
|
||||||
bindSimplePositionData(simpleHolder, posModel);
|
bindSimplePositionData(simpleHolder, posModel);
|
||||||
// 2. 初始化+绑定简单模式任务列表视图(仅显示已启用任务)
|
// 2. 重新初始化+绑定简单模式任务视图(复用后从服务同步最新任务,避免数据丢失)
|
||||||
initAndBindSimpleTaskView(simpleHolder.ptlvSimpleTasks, posId, mainService);
|
initAndBindSimpleTaskView(simpleHolder.ptlvSimpleTasks, posId, mainService);
|
||||||
// 3. 缓存简单模式任务视图+距离控件
|
// 3. 缓存/更新简单模式任务视图+距离控件(覆盖旧缓存,确保引用最新控件)
|
||||||
mSimpleTaskViewMap.put(posId, simpleHolder.ptlvSimpleTasks);
|
mSimpleTaskViewMap.put(posId, simpleHolder.ptlvSimpleTasks);
|
||||||
mPosDistanceViewMap.put(posId, simpleHolder.tvSimpleDistance);
|
mPosDistanceViewMap.put(posId, simpleHolder.tvSimpleDistance);
|
||||||
|
|
||||||
} else if (holder instanceof EditViewHolder) {
|
} else if (holder instanceof EditViewHolder) {
|
||||||
|
LogUtils.d(TAG, "instanceof EditViewHolder(复用/新创建):位置ID=" + posId);
|
||||||
EditViewHolder editHolder = (EditViewHolder) holder;
|
EditViewHolder editHolder = (EditViewHolder) holder;
|
||||||
// 1. 绑定位置基础数据(经纬度/备注/距离/距离开关)
|
// 1. 重新绑定位置基础数据(经纬度/备注/距离/距离开关,复用后显示最新状态)
|
||||||
bindEditPositionData(editHolder, posModel, position);
|
bindEditPositionData(editHolder, posModel, position);
|
||||||
// 2. 初始化+绑定编辑模式任务列表视图(支持增删改查)
|
// 2. 重新初始化+绑定编辑模式任务视图(复用后同步服务最新任务,支持增删改)
|
||||||
initAndBindEditTaskView(editHolder.ptlvEditTasks, posId, mainService, editHolder.btnAddTask);
|
initAndBindEditTaskView(editHolder.ptlvEditTasks, posId, mainService, editHolder.btnAddTask);
|
||||||
// 3. 缓存编辑模式任务视图+距离控件
|
// 3. 缓存/更新编辑模式任务视图+距离控件(覆盖旧缓存,确保引用最新控件)
|
||||||
mEditTaskViewMap.put(posId, editHolder.ptlvEditTasks);
|
mEditTaskViewMap.put(posId, editHolder.ptlvEditTasks);
|
||||||
mPosDistanceViewMap.put(posId, editHolder.tvEditDistance);
|
mPosDistanceViewMap.put(posId, editHolder.tvEditDistance);
|
||||||
}
|
}
|
||||||
@@ -157,39 +157,38 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
@Override
|
@Override
|
||||||
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
|
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
|
||||||
super.onViewDetachedFromWindow(holder);
|
super.onViewDetachedFromWindow(holder);
|
||||||
// 视图离开屏幕时:清空对应控件缓存+释放任务列表视图资源(移除未定义的onDestroy())
|
// 核心修改:仅清理「无效/已回收」的控件缓存,不释放关键资源(支持复用后重新绑定)
|
||||||
PositionModel posModel = getPositionByIndex(holder.getAdapterPosition());
|
PositionModel posModel = getPositionByIndex(holder.getAdapterPosition());
|
||||||
if (posModel == null || TextUtils.isEmpty(posModel.getPositionId())) {
|
if (posModel == null || TextUtils.isEmpty(posModel.getPositionId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String posId = posModel.getPositionId();
|
String posId = posModel.getPositionId();
|
||||||
|
|
||||||
// 1. 移除距离控件缓存
|
// 1. 清理「已脱离视图树/无效」的距离控件缓存(保留有效控件供局部更新)
|
||||||
if (mPosDistanceViewMap.containsKey(posId)) {
|
if (mPosDistanceViewMap.containsKey(posId)) {
|
||||||
|
TextView distanceView = mPosDistanceViewMap.get(posId);
|
||||||
|
if (distanceView == null || !distanceView.isAttachedToWindow()) {
|
||||||
mPosDistanceViewMap.remove(posId);
|
mPosDistanceViewMap.remove(posId);
|
||||||
LogUtils.d(TAG, "视图脱离屏幕:移除位置ID=" + posId + "的距离控件缓存");
|
LogUtils.d(TAG, "视图脱离屏幕:移除无效距离控件缓存(位置ID=" + posId + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 释放简单模式任务视图资源(清空数据+解绑监听,替代onDestroy())
|
// 2. 清理「已脱离视图树/无效」的简单模式任务视图缓存(不解绑监听/不清空数据,复用后重新同步)
|
||||||
if (holder instanceof SimpleViewHolder && mSimpleTaskViewMap.containsKey(posId)) {
|
if (holder instanceof SimpleViewHolder && mSimpleTaskViewMap.containsKey(posId)) {
|
||||||
PositionTaskListView taskView = mSimpleTaskViewMap.get(posId);
|
PositionTaskListView taskView = mSimpleTaskViewMap.get(posId);
|
||||||
if (taskView != null) {
|
if (taskView == null || !taskView.isAttachedToWindow()) {
|
||||||
taskView.clearData(); // 清空任务数据(假设视图已实现该方法,用于释放列表数据)
|
|
||||||
taskView.setOnTaskUpdatedListener(null); // 解绑任务更新监听,避免内存泄漏
|
|
||||||
}
|
|
||||||
mSimpleTaskViewMap.remove(posId);
|
mSimpleTaskViewMap.remove(posId);
|
||||||
LogUtils.d(TAG, "简单模式视图脱离屏幕:释放任务列表视图资源(位置ID=" + posId + ")");
|
LogUtils.d(TAG, "简单模式视图脱离屏幕:移除无效任务视图缓存(位置ID=" + posId + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 释放编辑模式任务视图资源(清空数据+解绑监听,替代onDestroy())
|
// 3. 清理「已脱离视图树/无效」的编辑模式任务视图缓存(同上,保留数据供复用)
|
||||||
if (holder instanceof EditViewHolder && mEditTaskViewMap.containsKey(posId)) {
|
if (holder instanceof EditViewHolder && mEditTaskViewMap.containsKey(posId)) {
|
||||||
PositionTaskListView taskView = mEditTaskViewMap.get(posId);
|
PositionTaskListView taskView = mEditTaskViewMap.get(posId);
|
||||||
if (taskView != null) {
|
if (taskView == null || !taskView.isAttachedToWindow()) {
|
||||||
taskView.clearData(); // 清空任务数据
|
|
||||||
taskView.setOnTaskUpdatedListener(null); // 解绑任务更新监听
|
|
||||||
}
|
|
||||||
mEditTaskViewMap.remove(posId);
|
mEditTaskViewMap.remove(posId);
|
||||||
LogUtils.d(TAG, "编辑模式视图脱离屏幕:释放任务列表视图资源(位置ID=" + posId + ")");
|
LogUtils.d(TAG, "编辑模式视图脱离屏幕:移除无效任务视图缓存(位置ID=" + posId + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,10 +198,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 位置数据绑定(分简单/编辑模式,独立逻辑解耦)
|
// 位置数据绑定(保留原有逻辑,确保复用后数据最新)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
/**
|
/**
|
||||||
* 绑定简单模式位置数据(仅显示,无编辑操作)
|
* 绑定简单模式位置数据(仅显示,无编辑操作)—— 复用后重新执行,显示最新数据
|
||||||
*/
|
*/
|
||||||
private void bindSimplePositionData(SimpleViewHolder holder, final PositionModel posModel) {
|
private void bindSimplePositionData(SimpleViewHolder holder, final PositionModel posModel) {
|
||||||
// 1. 经纬度显示(保留6位小数,格式统一)
|
// 1. 经纬度显示(保留6位小数,格式统一)
|
||||||
@@ -211,9 +210,9 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
|
|
||||||
// 2. 备注显示(无备注时显示默认文本)
|
// 2. 备注显示(无备注时显示默认文本)
|
||||||
String memo = posModel.getMemo();
|
String memo = posModel.getMemo();
|
||||||
holder.tvSimpleMemo.setText("备注:" + (TextUtils.isEmpty(memo)? DEFAULT_MEMO : memo));
|
holder.tvSimpleMemo.setText("备注:" + (TextUtils.isEmpty(memo) ? DEFAULT_MEMO : memo));
|
||||||
|
|
||||||
// 3. 实时距离显示(按状态区分文本+颜色)
|
// 3. 实时距离显示(按状态区分文本+颜色——复用后重新计算显示最新距离)
|
||||||
updateDistanceDisplay(holder.tvSimpleDistance, posModel);
|
updateDistanceDisplay(holder.tvSimpleDistance, posModel);
|
||||||
|
|
||||||
// 4. 点击切换到编辑模式
|
// 4. 点击切换到编辑模式
|
||||||
@@ -229,7 +228,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 绑定编辑模式位置数据(支持备注修改/距离开关/删除/保存)
|
* 绑定编辑模式位置数据(支持备注修改/距离开关/删除/保存)—— 复用后重新执行,恢复编辑状态
|
||||||
*/
|
*/
|
||||||
private void bindEditPositionData(final EditViewHolder holder, final PositionModel posModel, final int position) {
|
private void bindEditPositionData(final EditViewHolder holder, final PositionModel posModel, final int position) {
|
||||||
final String posId = posModel.getPositionId();
|
final String posId = posModel.getPositionId();
|
||||||
@@ -238,7 +237,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
holder.tvEditLon.setText(String.format("经度:%.6f", posModel.getLongitude()));
|
holder.tvEditLon.setText(String.format("经度:%.6f", posModel.getLongitude()));
|
||||||
holder.tvEditLat.setText(String.format("纬度:%.6f", posModel.getLatitude()));
|
holder.tvEditLat.setText(String.format("纬度:%.6f", posModel.getLatitude()));
|
||||||
|
|
||||||
// 2. 备注编辑(填充现有备注,光标定位到末尾)
|
// 2. 备注编辑(填充现有备注,光标定位到末尾——复用后恢复输入状态)
|
||||||
String memo = posModel.getMemo();
|
String memo = posModel.getMemo();
|
||||||
if (!TextUtils.isEmpty(memo)) {
|
if (!TextUtils.isEmpty(memo)) {
|
||||||
holder.etEditMemo.setText(memo);
|
holder.etEditMemo.setText(memo);
|
||||||
@@ -247,10 +246,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
holder.etEditMemo.setText("");
|
holder.etEditMemo.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 实时距离显示(与简单模式逻辑一致)
|
// 3. 实时距离显示(与简单模式逻辑一致——复用后显示最新距离)
|
||||||
updateDistanceDisplay(holder.tvEditDistance, posModel);
|
updateDistanceDisplay(holder.tvEditDistance, posModel);
|
||||||
|
|
||||||
// 4. 距离开关状态(匹配位置模型中的启用状态)
|
// 4. 距离开关状态(匹配位置模型中的启用状态——复用后恢复开关状态)
|
||||||
holder.rgDistanceSwitch.check(posModel.isEnableRealPositionDistance()
|
holder.rgDistanceSwitch.check(posModel.isEnableRealPositionDistance()
|
||||||
? R.id.rb_distance_enable
|
? R.id.rb_distance_enable
|
||||||
: R.id.rb_distance_disable);
|
: R.id.rb_distance_disable);
|
||||||
@@ -312,10 +311,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// PositionTaskListView 集成(分简单/编辑模式,差异化初始化+绑定)
|
// PositionTaskListView 集成(强化复用逻辑:复用后重新同步服务数据,确保数据不丢失)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
/**
|
/**
|
||||||
* 初始化+绑定简单模式任务列表视图(仅显示已启用任务,无编辑操作)
|
* 初始化+绑定简单模式任务列表视图——复用后重新执行,从服务同步最新任务
|
||||||
*/
|
*/
|
||||||
private void initAndBindSimpleTaskView(PositionTaskListView taskView, final String posId, MainService mainService) {
|
private void initAndBindSimpleTaskView(PositionTaskListView taskView, final String posId, MainService mainService) {
|
||||||
if (taskView == null || TextUtils.isEmpty(posId) || mainService == null) {
|
if (taskView == null || TextUtils.isEmpty(posId) || mainService == null) {
|
||||||
@@ -323,26 +322,26 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 初始化任务视图(绑定MainService+当前位置ID,假设视图已实现init方法)
|
// 1. 初始化任务视图(绑定MainService+当前位置ID——复用后重新绑定,确保服务引用有效)
|
||||||
taskView.init(mainService, posId);
|
taskView.init(mainService, posId);
|
||||||
// 2. 设置为简单模式(仅展示,隐藏编辑按钮,需视图支持该状态设置)
|
// 2. 设置为简单模式(仅展示,隐藏编辑按钮——复用后恢复视图模式)
|
||||||
taskView.setViewStatus(PositionTaskListView.VIEW_MODE_SIMPLE);
|
taskView.setViewStatus(PositionTaskListView.VIEW_MODE_SIMPLE);
|
||||||
// 3. 同步任务数据(从MainService拉取当前位置已启用任务)
|
// 3. 关键:复用后强制从服务同步最新任务(避免显示旧数据,核心修复点)
|
||||||
taskView.syncTasksFromMainService();
|
taskView.syncTasksFromMainService();
|
||||||
|
|
||||||
// 4. 任务更新回调(服务任务变化时重新同步)
|
// 4. 任务更新回调(服务任务变化时重新同步——复用后重新绑定回调,避免监听失效)
|
||||||
taskView.setOnTaskUpdatedListener(new PositionTaskListView.OnTaskUpdatedListener() {
|
taskView.setOnTaskUpdatedListener(new PositionTaskListView.OnTaskUpdatedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onTaskUpdated(String positionId, ArrayList<PositionTaskModel> updatedTasks) {
|
public void onTaskUpdated(String positionId, ArrayList updatedTasks) {
|
||||||
LogUtils.d(TAG, "简单模式任务更新:位置ID=" + positionId + ",已启用任务数=" + updatedTasks.size());
|
LogUtils.d(TAG, "简单模式任务更新:位置ID=" + positionId + ",已启用任务数=" + updatedTasks.size());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
LogUtils.d(TAG, "初始化简单模式任务视图完成:位置ID=" + posId);
|
LogUtils.d(TAG, "初始化/复用简单模式任务视图完成:位置ID=" + posId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化+绑定编辑模式任务列表视图(支持增删改查,关联新增任务按钮)
|
- 初始化+绑定编辑模式任务列表视图——复用后重新执行,从服务同步最新任务+恢复编辑功能
|
||||||
*/
|
*/
|
||||||
private void initAndBindEditTaskView(final PositionTaskListView taskView, final String posId,
|
private void initAndBindEditTaskView(final PositionTaskListView taskView, final String posId,
|
||||||
MainService mainService, Button btnAddTask) {
|
MainService mainService, Button btnAddTask) {
|
||||||
@@ -350,15 +349,12 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
LogUtils.w(TAG, "初始化编辑模式任务视图失败:参数无效(posId=" + posId + ",btnAddTask=" + btnAddTask + ")");
|
LogUtils.w(TAG, "初始化编辑模式任务视图失败:参数无效(posId=" + posId + ",btnAddTask=" + btnAddTask + ")");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 1. 初始化任务视图(绑定MainService+当前位置ID——复用后重新绑定,确保服务引用有效)
|
||||||
// 1. 初始化任务视图(绑定MainService+当前位置ID)
|
|
||||||
taskView.init(mainService, posId);
|
taskView.init(mainService, posId);
|
||||||
// 2. 设置为编辑模式(显示编辑/删除按钮,支持修改)
|
// 2. 设置为编辑模式(显示编辑/删除按钮——复用后恢复视图模式)
|
||||||
taskView.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT);
|
taskView.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT);
|
||||||
// 3. 同步任务数据(从MainService拉取当前位置所有任务)
|
// 3. 关键:复用后强制从服务同步最新任务(避免显示旧数据,核心修复点)
|
||||||
taskView.syncTasksFromMainService();
|
taskView.syncTasksFromMainService();// 4. 绑定“新增任务”按钮逻辑(复用后重新绑定点击事件,避免按钮点击失效)
|
||||||
|
|
||||||
// 4. 绑定“新增任务”按钮逻辑(点击创建默认任务,通过任务视图同步到服务)
|
|
||||||
btnAddTask.setOnClickListener(new View.OnClickListener() {
|
btnAddTask.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@@ -369,54 +365,44 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
newTask.setTaskDescription(DEFAULT_TASK_DESC); // 默认描述
|
newTask.setTaskDescription(DEFAULT_TASK_DESC); // 默认描述
|
||||||
newTask.setDiscussDistance(DEFAULT_TASK_DISTANCE); // 默认触发距离(50米)
|
newTask.setDiscussDistance(DEFAULT_TASK_DISTANCE); // 默认触发距离(50米)
|
||||||
newTask.setIsEnable(true); // 默认启用
|
newTask.setIsEnable(true); // 默认启用
|
||||||
newTask.setIsBingo(false); // 初始未触发
|
newTask.setIsBingo(false); // 初始未触发// 调用任务视图的新增方法(假设视图已实现addNewTask,内部同步MainService)
|
||||||
|
|
||||||
// 调用任务视图的新增方法(假设视图已实现addNewTask,内部同步MainService)
|
|
||||||
taskView.addNewTask(newTask);
|
taskView.addNewTask(newTask);
|
||||||
hideSoftKeyboard(v); // 隐藏软键盘,提升体验
|
hideSoftKeyboard(v); // 隐藏软键盘,提升体验
|
||||||
LogUtils.d(TAG, "编辑模式新增任务:位置ID=" + posId + ",任务ID=" + newTask.getTaskId());
|
LogUtils.d(TAG, "编辑模式新增任务:位置ID=" + posId + ",任务ID=" + newTask.getTaskId());
|
||||||
}
|
}
|
||||||
});
|
});// 5. 任务更新回调(通知外部任务变化——复用后重新绑定回调,确保交互正常)
|
||||||
|
|
||||||
// 5. 任务更新回调(通知外部任务变化,如Activity需要联动)
|
|
||||||
taskView.setOnTaskUpdatedListener(new PositionTaskListView.OnTaskUpdatedListener() {
|
taskView.setOnTaskUpdatedListener(new PositionTaskListView.OnTaskUpdatedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onTaskUpdated(String positionId, ArrayList<PositionTaskModel> updatedTasks) {
|
public void onTaskUpdated(String positionId, ArrayList updatedTasks) {
|
||||||
LogUtils.d(TAG, "编辑模式任务更新:位置ID=" + positionId + ",当前任务数=" + updatedTasks.size());
|
LogUtils.d(TAG, "编辑模式任务更新:位置ID=" + positionId + ",当前任务数=" + updatedTasks.size());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
LogUtils.d(TAG, "初始化/复用编辑模式任务视图完成:位置ID=" + posId);
|
||||||
LogUtils.d(TAG, "初始化编辑模式任务视图完成:位置ID=" + posId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 工具方法(距离显示/数据校验/控件管理,Java 7 语法适配)
|
// 工具方法(保留原有逻辑,适配资源复用场景)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
/**
|
/**
|
||||||
* 更新距离显示(按状态区分文本和颜色,提升视觉区分度)
|
|
||||||
|
- 更新距离显示(复用后重新执行,确保显示最新距离+颜色——适配资源复用)
|
||||||
*/
|
*/
|
||||||
private void updateDistanceDisplay(TextView distanceView, PositionModel posModel) {
|
private void updateDistanceDisplay(TextView distanceView, PositionModel posModel) {
|
||||||
if (distanceView == null || posModel == null) {
|
if (distanceView == null || posModel == null) {
|
||||||
LogUtils.w(TAG, "更新距离显示失败:参数为空(控件/位置模型)");
|
LogUtils.w(TAG, "更新距离显示失败:参数为空(控件/位置模型)");
|
||||||
return;
|
return;
|
||||||
}
|
}// 场景1:距离未启用(灰色文本)
|
||||||
|
|
||||||
// 场景1:距离未启用(灰色文本)
|
|
||||||
if (!posModel.isEnableRealPositionDistance()) {
|
if (!posModel.isEnableRealPositionDistance()) {
|
||||||
distanceView.setText(DISTANCE_DISABLED);
|
distanceView.setText(DISTANCE_DISABLED);
|
||||||
distanceView.setTextColor(mContext.getResources().getColor(R.color.gray));
|
distanceView.setTextColor(mContext.getResources().getColor(R.color.gray));
|
||||||
return;
|
return;
|
||||||
}
|
}// 场景2:距离计算失败(红色文本,用-1标记失败状态)
|
||||||
|
|
||||||
// 场景2:距离计算失败(红色文本,用-1标记失败状态)
|
|
||||||
double distance = posModel.getRealPositionDistance();
|
double distance = posModel.getRealPositionDistance();
|
||||||
if (distance < 0) {
|
if (distance < 0) {
|
||||||
distanceView.setText(DISTANCE_ERROR);
|
distanceView.setText(DISTANCE_ERROR);
|
||||||
distanceView.setTextColor(mContext.getResources().getColor(R.color.red));
|
distanceView.setTextColor(mContext.getResources().getColor(R.color.red));
|
||||||
return;
|
return;
|
||||||
}
|
}// 场景3:正常显示距离(按距离范围设置颜色——复用后重新计算颜色)
|
||||||
|
|
||||||
// 场景3:正常显示距离(按距离范围设置颜色)
|
|
||||||
distanceView.setText(String.format(DISTANCE_FORMAT, distance));
|
distanceView.setText(String.format(DISTANCE_FORMAT, distance));
|
||||||
if (distance <= 100) {
|
if (distance <= 100) {
|
||||||
distanceView.setTextColor(mContext.getResources().getColor(R.color.green)); // 近距离(≤100米)
|
distanceView.setTextColor(mContext.getResources().getColor(R.color.green)); // 近距离(≤100米)
|
||||||
@@ -428,7 +414,8 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据索引获取位置模型(容错处理,避免越界/空指针)
|
|
||||||
|
- 根据索引获取位置模型(容错处理,避免越界/空指针——适配复用后索引变化场景)
|
||||||
*/
|
*/
|
||||||
private PositionModel getPositionByIndex(int index) {
|
private PositionModel getPositionByIndex(int index) {
|
||||||
if (mCachedPositionList == null || index < 0 || index >= mCachedPositionList.size()) {
|
if (mCachedPositionList == null || index < 0 || index >= mCachedPositionList.size()) {
|
||||||
@@ -439,15 +426,14 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据位置ID获取列表索引(用于精准刷新视图)
|
|
||||||
|
- 根据位置ID获取列表索引(用于精准刷新视图——适配复用后视图位置变化)
|
||||||
*/
|
*/
|
||||||
private int getPositionIndexById(String positionId) {
|
private int getPositionIndexById(String positionId) {
|
||||||
if (TextUtils.isEmpty(positionId) || mCachedPositionList == null || mCachedPositionList.isEmpty()) {
|
if (TextUtils.isEmpty(positionId) || mCachedPositionList == null || mCachedPositionList.isEmpty()) {
|
||||||
LogUtils.w(TAG, "获取位置索引失败:参数无效(ID/缓存为空)");
|
LogUtils.w(TAG, "获取位置索引失败:参数无效(ID/缓存为空)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}// Java 7 增强for循环遍历(替代Lambda,适配语法)
|
||||||
|
|
||||||
// Java 7 增强for循环遍历(替代Lambda,适配语法)
|
|
||||||
for (int i = 0; i < mCachedPositionList.size(); i++) {
|
for (int i = 0; i < mCachedPositionList.size(); i++) {
|
||||||
PositionModel pos = mCachedPositionList.get(i);
|
PositionModel pos = mCachedPositionList.get(i);
|
||||||
if (positionId.equals(pos.getPositionId())) {
|
if (positionId.equals(pos.getPositionId())) {
|
||||||
@@ -459,29 +445,28 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 局部更新距离UI(仅更新指定位置的距离,避免全量刷新卡顿)
|
|
||||||
|
- 局部更新距离UI(仅更新指定位置的距离,避免全量刷新卡顿——适配复用后控件缓存有效场景)
|
||||||
*/
|
*/
|
||||||
public void updateSinglePositionDistance(String positionId) {
|
public void updateSinglePositionDistance(String positionId) {
|
||||||
if (TextUtils.isEmpty(positionId) || mPosDistanceViewMap.isEmpty()) {
|
if (TextUtils.isEmpty(positionId) || mPosDistanceViewMap.isEmpty()) {
|
||||||
LogUtils.w(TAG, "局部更新距离失败:ID无效或无控件缓存(ID=" + positionId + ")");
|
LogUtils.w(TAG, "局部更新距离失败:ID无效或无控件缓存(ID=" + positionId + ")");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 获取服务端最新位置数据(带重试,避免服务临时回收)
|
// 1. 获取服务端最新位置数据(带重试,避免服务临时回收)
|
||||||
MainService mainService = getMainServiceWithRetry(2);
|
MainService mainService = getMainServiceWithRetry(2);
|
||||||
if (mainService == null) {
|
if (mainService == null) {
|
||||||
LogUtils.e(TAG, "局部更新距离失败:无法获取MainService");
|
LogUtils.e(TAG, "局部更新距离失败:无法获取MainService");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionModel latestPos = null;
|
PositionModel latestPos = null;
|
||||||
try {
|
try {
|
||||||
ArrayList<PositionModel> servicePosList = mainService.getPositionList();
|
ArrayList servicePosList = mainService.getPositionList();
|
||||||
if (servicePosList != null && !servicePosList.isEmpty()) {
|
if (servicePosList != null && !servicePosList.isEmpty()) {
|
||||||
// Java 7 迭代器遍历,避免ConcurrentModificationException
|
// Java 7 迭代器遍历,避免ConcurrentModificationException
|
||||||
Iterator<PositionModel> iter = servicePosList.iterator();
|
Iterator iter = servicePosList.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
PositionModel pos = iter.next();
|
PositionModel pos = (PositionModel)iter.next();
|
||||||
if (positionId.equals(pos.getPositionId())) {
|
if (positionId.equals(pos.getPositionId())) {
|
||||||
latestPos = pos;
|
latestPos = pos;
|
||||||
break;
|
break;
|
||||||
@@ -491,14 +476,11 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.d(TAG, "获取最新位置数据失败(ID=" + positionId + ")" + e);
|
LogUtils.d(TAG, "获取最新位置数据失败(ID=" + positionId + ")" + e);
|
||||||
return;
|
return;
|
||||||
}
|
}if (latestPos == null) {
|
||||||
|
|
||||||
if (latestPos == null) {
|
|
||||||
LogUtils.w(TAG, "局部更新距离失败:未找到位置ID=" + positionId);
|
LogUtils.w(TAG, "局部更新距离失败:未找到位置ID=" + positionId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 2. 更新距离控件(确保主线程操作,避免跨线程异常——适配复用后控件已重新绑定)
|
||||||
// 2. 更新距离控件(确保主线程操作,避免跨线程异常)
|
|
||||||
final TextView distanceView = mPosDistanceViewMap.get(positionId);
|
final TextView distanceView = mPosDistanceViewMap.get(positionId);
|
||||||
if (distanceView != null && distanceView.isAttachedToWindow()) {
|
if (distanceView != null && distanceView.isAttachedToWindow()) {
|
||||||
final PositionModel finalLatestPos = latestPos;
|
final PositionModel finalLatestPos = latestPos;
|
||||||
@@ -510,20 +492,19 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
});
|
});
|
||||||
LogUtils.d(TAG, "局部更新距离完成:位置ID=" + positionId + ",距离=" + latestPos.getRealPositionDistance() + "米");
|
LogUtils.d(TAG, "局部更新距离完成:位置ID=" + positionId + ",距离=" + latestPos.getRealPositionDistance() + "米");
|
||||||
} else {
|
} else {
|
||||||
mPosDistanceViewMap.remove(positionId); // 移除无效控件缓存
|
mPosDistanceViewMap.remove(positionId); // 移除无效控件缓存(如视图已被销毁)
|
||||||
LogUtils.w(TAG, "局部更新距离失败:控件已回收/脱离视图树(ID=" + positionId + ")");
|
LogUtils.w(TAG, "局部更新距离失败:控件已回收/脱离视图树(ID=" + positionId + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全量更新位置数据(从服务同步最新数据,过滤无效/重复项)
|
- 全量更新位置数据(从服务同步最新数据,过滤无效/重复项——适配复用后全量刷新场景)
|
||||||
*/
|
*/
|
||||||
public void updateAllPositionData(ArrayList<PositionModel> newPosList) {
|
public void updateAllPositionData(ArrayList<PositionModel> newPosList) {
|
||||||
if (newPosList == null) {
|
if (newPosList == null) {
|
||||||
LogUtils.w(TAG, "全量更新位置数据失败:新列表为空");
|
LogUtils.w(TAG, "全量更新位置数据失败:新列表为空");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 过滤无效位置(校验核心字段:ID/经纬度合法)
|
// 1. 过滤无效位置(校验核心字段:ID/经纬度合法)
|
||||||
ArrayList<PositionModel> validPosList = new ArrayList<PositionModel>();
|
ArrayList<PositionModel> validPosList = new ArrayList<PositionModel>();
|
||||||
for (PositionModel pos : newPosList) {
|
for (PositionModel pos : newPosList) {
|
||||||
@@ -535,18 +516,15 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
validPosList.add(pos);
|
validPosList.add(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 去重(按位置ID去重,保留服务端最新数据)
|
// 2. 去重(按位置ID去重,保留服务端最新数据)
|
||||||
ConcurrentHashMap<String, PositionModel> uniquePosMap = new ConcurrentHashMap<String, PositionModel>();
|
ConcurrentHashMap<String, PositionModel> uniquePosMap = new ConcurrentHashMap<String, PositionModel>();
|
||||||
for (PositionModel pos : validPosList) {
|
for (PositionModel pos : validPosList) {
|
||||||
uniquePosMap.put(pos.getPositionId(), pos); // 相同ID覆盖,保留最新
|
uniquePosMap.put(pos.getPositionId(), pos); // 相同ID覆盖,保留最新
|
||||||
}
|
}
|
||||||
ArrayList<PositionModel> uniquePosList = new ArrayList<PositionModel>(uniquePosMap.values());
|
ArrayList uniquePosList = new ArrayList(uniquePosMap.values());// 3. 同步到本地缓存+刷新UI(刷新后触发onBind,自动重新绑定资源)
|
||||||
|
|
||||||
// 3. 同步到本地缓存+刷新UI
|
|
||||||
this.mCachedPositionList.clear();
|
this.mCachedPositionList.clear();
|
||||||
this.mCachedPositionList.addAll(uniquePosList);
|
this.mCachedPositionList.addAll(uniquePosList);
|
||||||
// 清空旧控件缓存(避免引用失效数据)
|
// 清空旧控件缓存(避免引用失效数据,刷新后重新缓存新控件)
|
||||||
mPosDistanceViewMap.clear();
|
mPosDistanceViewMap.clear();
|
||||||
mSimpleTaskViewMap.clear();
|
mSimpleTaskViewMap.clear();
|
||||||
mEditTaskViewMap.clear();
|
mEditTaskViewMap.clear();
|
||||||
@@ -555,36 +533,33 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 隐藏软键盘(编辑完成后调用,提升用户体验)
|
- 隐藏软键盘(编辑完成后调用,提升用户体验——适配复用后软键盘残留问题)
|
||||||
*/
|
*/
|
||||||
private void hideSoftKeyboard(View view) {
|
private void hideSoftKeyboard(View view) {
|
||||||
if (mContext == null || view == null) {
|
if (mContext == null || view == null) {
|
||||||
LogUtils.w(TAG, "隐藏软键盘失败:参数为空(上下文/视图)");
|
LogUtils.w(TAG, "隐藏软键盘失败:参数为空(上下文/视图)");
|
||||||
return;
|
return;
|
||||||
}
|
}InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
|
||||||
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
||||||
if (imm != null) {
|
if (imm != null) {
|
||||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0); // 强制隐藏
|
imm.hideSoftInputFromWindow(view.getWindowToken(), 0); // 强制隐藏
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 带重试的服务获取(解决弱引用临时回收问题,最多重试2次)
|
- 带重试的服务获取(解决弱引用临时回收问题,最多重试2次——适配复用后服务引用失效场景)
|
||||||
*/
|
*/
|
||||||
private MainService getMainServiceWithRetry(int retryCount) {
|
private MainService getMainServiceWithRetry(int retryCount) {
|
||||||
MainService mainService = mMainServiceRef.get();
|
MainService mainService = mMainServiceRef.get();
|
||||||
if (mainService != null) {
|
if (mainService != null) {
|
||||||
return mainService;
|
return mainService;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重试逻辑:每次间隔100ms,避免频繁重试
|
// 重试逻辑:每次间隔100ms,避免频繁重试
|
||||||
for (int i = 0; i < retryCount; i++) {
|
for (int i = 0; i < retryCount; i++) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
mainService = mMainServiceRef.get();
|
mainService = mMainServiceRef.get();
|
||||||
if (mainService != null) {
|
if (mainService != null) {
|
||||||
LogUtils.d(TAG, "重试获取MainService成功(第" + (i+1) + "次)");
|
LogUtils.d(TAG, "重试获取MainService成功(第" + (i + 1) + "次)");
|
||||||
return mainService;
|
return mainService;
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -592,41 +567,39 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
Thread.currentThread().interrupt(); // 恢复中断状态
|
Thread.currentThread().interrupt(); // 恢复中断状态
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}LogUtils.e(TAG, "重试" + retryCount + "次后仍未获取到MainService");
|
||||||
|
|
||||||
LogUtils.e(TAG, "重试" + retryCount + "次后仍未获取到MainService");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 实现 MainService.TaskUpdateListener 接口(服务任务变化时回调)
|
// 实现 MainService.TaskUpdateListener 接口(服务任务变化时回调——适配复用后任务同步)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@Override
|
@Override
|
||||||
public void onTaskUpdated() {
|
public void onTaskUpdated() {
|
||||||
LogUtils.d(TAG, "收到MainService任务更新通知,同步所有任务列表视图");
|
LogUtils.d(TAG, "收到MainService任务更新通知,同步所有任务列表视图(含复用视图)");
|
||||||
|
|
||||||
// 1. 同步简单模式任务视图(仅显示已启用任务)
|
// 1. 同步简单模式任务视图(仅显示已启用任务——适配复用后视图已重新缓存)
|
||||||
if (!mSimpleTaskViewMap.isEmpty()) {
|
if (!mSimpleTaskViewMap.isEmpty()) {
|
||||||
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mSimpleTaskViewMap.entrySet().iterator();
|
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mSimpleTaskViewMap.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
ConcurrentHashMap.Entry<String, PositionTaskListView> entry = iter.next();
|
ConcurrentHashMap.Entry<String, PositionTaskListView> entry = iter.next();
|
||||||
PositionTaskListView taskView = entry.getValue();
|
PositionTaskListView taskView = entry.getValue();
|
||||||
if (taskView != null && taskView.isAttachedToWindow()) {
|
if (taskView != null && taskView.isAttachedToWindow()) {
|
||||||
taskView.syncTasksFromMainService(); // 从服务同步最新任务
|
taskView.syncTasksFromMainService(); // 从服务同步最新任务(复用后也能更新)
|
||||||
} else {
|
} else {
|
||||||
iter.remove(); // 移除无效视图缓存
|
iter.remove(); // 移除无效视图缓存(如视图已脱离屏幕且未复用)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 同步编辑模式任务视图(支持编辑的全量任务)
|
// 2. 同步编辑模式任务视图(支持编辑的全量任务——适配复用后视图已重新缓存)
|
||||||
if (!mEditTaskViewMap.isEmpty()) {
|
if (!mEditTaskViewMap.isEmpty()) {
|
||||||
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mEditTaskViewMap.entrySet().iterator();
|
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mEditTaskViewMap.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
ConcurrentHashMap.Entry<String, PositionTaskListView> entry = iter.next();
|
ConcurrentHashMap.Entry<String, PositionTaskListView> entry = iter.next();
|
||||||
PositionTaskListView taskView = entry.getValue();
|
PositionTaskListView taskView = entry.getValue();
|
||||||
if (taskView != null && taskView.isAttachedToWindow()) {
|
if (taskView != null && taskView.isAttachedToWindow()) {
|
||||||
taskView.syncTasksFromMainService(); // 从服务同步最新任务
|
taskView.syncTasksFromMainService(); // 从服务同步最新任务(复用后也能更新)
|
||||||
} else {
|
} else {
|
||||||
iter.remove(); // 移除无效视图缓存
|
iter.remove(); // 移除无效视图缓存
|
||||||
}
|
}
|
||||||
@@ -635,7 +608,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 回调设置方法(供Activity绑定交互逻辑)
|
// 回调设置方法(供Activity绑定交互逻辑——适配复用后回调不失效)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
public void setOnDeleteClickListener(OnDeleteClickListener listener) {
|
public void setOnDeleteClickListener(OnDeleteClickListener listener) {
|
||||||
this.mOnDeleteListener = listener;
|
this.mOnDeleteListener = listener;
|
||||||
@@ -646,7 +619,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 资源释放(Activity销毁时调用,彻底释放引用,避免内存泄漏)
|
// 资源释放(Activity销毁时调用,彻底释放引用,避免内存泄漏——保留原有安全逻辑)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
public void release() {
|
public void release() {
|
||||||
// 1. 反注册MainService任务监听(解除服务绑定)
|
// 1. 反注册MainService任务监听(解除服务绑定)
|
||||||
@@ -656,7 +629,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
LogUtils.d(TAG, "已反注册MainService任务监听");
|
LogUtils.d(TAG, "已反注册MainService任务监听");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 释放简单模式任务视图资源(清空数据+解绑监听,替代onDestroy())
|
// 2. 释放简单模式任务视图资源(清空数据+解绑监听——仅在Activity销毁时执行,不复用场景)
|
||||||
if (!mSimpleTaskViewMap.isEmpty()) {
|
if (!mSimpleTaskViewMap.isEmpty()) {
|
||||||
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mSimpleTaskViewMap.entrySet().iterator();
|
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mSimpleTaskViewMap.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
@@ -669,7 +642,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 释放编辑模式任务视图资源(清空数据+解绑监听,替代onDestroy())
|
// 3. 释放编辑模式任务视图资源(清空数据+解绑监听——仅在Activity销毁时执行)
|
||||||
if (!mEditTaskViewMap.isEmpty()) {
|
if (!mEditTaskViewMap.isEmpty()) {
|
||||||
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mEditTaskViewMap.entrySet().iterator();
|
Iterator<ConcurrentHashMap.Entry<String, PositionTaskListView>> iter = mEditTaskViewMap.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
@@ -682,7 +655,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 清空其他缓存+置空引用
|
// 4. 清空其他缓存+置空引用(彻底释放,避免内存泄漏)
|
||||||
mPosDistanceViewMap.clear();
|
mPosDistanceViewMap.clear();
|
||||||
if (mCachedPositionList != null) {
|
if (mCachedPositionList != null) {
|
||||||
mCachedPositionList.clear();
|
mCachedPositionList.clear();
|
||||||
@@ -697,7 +670,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
// 静态内部类:ViewHolder(与布局严格对应,避免外部引用导致内存泄漏)
|
// 静态内部类:ViewHolder(与布局严格对应,避免外部引用导致内存泄漏)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
/**
|
/**
|
||||||
* 简单模式ViewHolder(对应 item_position_simple.xml,含简单模式任务列表视图)
|
- 简单模式ViewHolder(对应 item_position_simple.xml,含简单模式任务列表视图)
|
||||||
*/
|
*/
|
||||||
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
|
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
|
||||||
TextView tvSimpleLon; // 经度显示
|
TextView tvSimpleLon; // 经度显示
|
||||||
@@ -705,7 +678,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
TextView tvSimpleMemo; // 备注显示
|
TextView tvSimpleMemo; // 备注显示
|
||||||
TextView tvSimpleDistance; // 距离显示
|
TextView tvSimpleDistance; // 距离显示
|
||||||
PositionTaskListView ptlvSimpleTasks; // 简单模式任务列表视图
|
PositionTaskListView ptlvSimpleTasks; // 简单模式任务列表视图
|
||||||
|
|
||||||
public SimpleViewHolder(View itemView) {
|
public SimpleViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
// 绑定布局控件(与XML中ID严格一致,避免运行时空指针)
|
// 绑定布局控件(与XML中ID严格一致,避免运行时空指针)
|
||||||
@@ -718,7 +690,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑模式ViewHolder(对应 item_position_edit.xml,含编辑模式任务列表视图)
|
- 编辑模式ViewHolder(对应 item_position_edit.xml,含编辑模式任务列表视图)
|
||||||
*/
|
*/
|
||||||
public static class EditViewHolder extends RecyclerView.ViewHolder {
|
public static class EditViewHolder extends RecyclerView.ViewHolder {
|
||||||
TextView tvEditLon; // 经度显示(不可编辑)
|
TextView tvEditLon; // 经度显示(不可编辑)
|
||||||
@@ -732,7 +704,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
Button btnAddTask; // 新增任务按钮
|
Button btnAddTask; // 新增任务按钮
|
||||||
TextView tvTaskCount; // 任务数量显示(兼容旧布局,可隐藏)
|
TextView tvTaskCount; // 任务数量显示(兼容旧布局,可隐藏)
|
||||||
PositionTaskListView ptlvEditTasks; // 编辑模式任务列表视图
|
PositionTaskListView ptlvEditTasks; // 编辑模式任务列表视图
|
||||||
|
|
||||||
public EditViewHolder(View itemView) {
|
public EditViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
// 绑定布局控件(与XML中ID严格一致,避免运行时空指针)
|
// 绑定布局控件(与XML中ID严格一致,避免运行时空指针)
|
||||||
@@ -752,88 +723,87 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 补充:PositionTaskListView 必要方法适配(确保视图类已实现以下基础方法)
|
// 补充:PositionTaskListView 必要方法适配(确保视图类已实现以下基础方法)
|
||||||
// (若视图类未实现,需在 PositionTaskListView 中添加对应逻辑)
|
// (若视图类未实现,需在 PositionTaskListView 中添加对应逻辑,否则复用后功能异常)
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
public static class PositionTaskListViewRequiredMethods {
|
public static class PositionTaskListViewRequiredMethods {
|
||||||
/**
|
/**
|
||||||
* 1. init 方法:初始化任务视图(绑定服务+位置ID)
|
1. - init 方法:初始化任务视图(绑定服务+位置ID——复用后重新绑定,确保服务引用有效)
|
||||||
* 需在 PositionTaskListView 中添加:
|
- 需在 PositionTaskListView 中添加:
|
||||||
* public void init(MainService mainService, String positionId) {
|
- public void init(MainService mainService, String positionId) {
|
||||||
* this.mMainServiceRef = new WeakReference<MainService>(mainService); // 弱引用服务
|
- this.mMainServiceRef = new WeakReference(mainService); // 弱引用服务,防泄漏
|
||||||
* this.mPositionId = positionId; // 绑定当前位置ID
|
- this.mPositionId = positionId; // 绑定当前位置ID(复用后更新为当前位置ID)
|
||||||
* }
|
- }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 2. setViewStatus 方法:设置视图模式(简单/编辑)
|
2. - setViewStatus 方法:设置视图模式(简单/编辑——复用后恢复对应模式UI)
|
||||||
* 需在 PositionTaskListView 中添加:
|
- 需在 PositionTaskListView 中添加:
|
||||||
* public static final int VIEW_MODE_SIMPLE = 0; // 仅显示
|
- public static final int VIEW_MODE_SIMPLE = 0; // 仅显示(隐藏编辑/删除按钮)
|
||||||
* public static final int VIEW_MODE_EDIT = 1; // 可编辑
|
- public static final int VIEW_MODE_EDIT = 1; // 可编辑(显示编辑/删除按钮)
|
||||||
* private int mViewMode;
|
- private int mViewMode;
|
||||||
* public void setViewStatus(int viewMode) {
|
- public void setViewStatus(int viewMode) {
|
||||||
* this.mViewMode = viewMode;
|
- this.mViewMode = viewMode;
|
||||||
* // 根据模式控制编辑/删除按钮显示(如简单模式隐藏,编辑模式显示)
|
- // 根据模式控制按钮显示:简单模式隐藏编辑按钮,编辑模式显示
|
||||||
* updateButtonVisibility();
|
- if (mEditBtn != null) mEditBtn.setVisibility(viewMode == VIEW_MODE_EDIT ? View.VISIBLE : View.GONE);
|
||||||
* }
|
- if (mDeleteBtn != null) mDeleteBtn.setVisibility(viewMode == VIEW_MODE_EDIT ? View.VISIBLE : View.GONE);
|
||||||
|
- }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 3. syncTasksFromMainService 方法:从服务同步任务数据
|
3. - syncTasksFromMainService 方法:从服务同步任务数据(复用后核心方法,避免旧数据)
|
||||||
* 需在 PositionTaskListView 中添加:
|
- 需在 PositionTaskListView 中添加:
|
||||||
* public void syncTasksFromMainService() {
|
- public void syncTasksFromMainService() {
|
||||||
* MainService mainService = mMainServiceRef.get();
|
- MainService mainService = mMainServiceRef.get();
|
||||||
* if (mainService == null || TextUtils.isEmpty(mPositionId)) return;
|
- if (mainService == null || TextUtils.isEmpty(mPositionId)) return;
|
||||||
* // 根据视图模式拉取任务(简单模式:已启用;编辑模式:所有)
|
- // 根据视图模式拉取对应任务:简单模式仅拉已启用,编辑模式拉全部
|
||||||
* ArrayList<PositionTaskModel> tasks = (mViewMode == VIEW_MODE_SIMPLE)
|
- ArrayList tasks = (mViewMode == VIEW_MODE_SIMPLE)
|
||||||
* ? mainService.getEnabledTasksByPositionId(mPositionId)
|
- ? mainService.getEnabledTasksByPositionId(mPositionId)
|
||||||
* : mainService.getTasksByPositionId(mPositionId);
|
- : mainService.getTasksByPositionId(mPositionId);
|
||||||
* // 更新列表显示(如设置Adapter数据)
|
- // 更新列表数据(刷新UI,确保复用后显示最新任务)
|
||||||
* setTaskList(tasks);
|
- if (mTaskAdapter != null) {
|
||||||
* }
|
- mTaskAdapter.setTaskList(tasks);
|
||||||
|
- mTaskAdapter.notifyDataSetChanged();
|
||||||
|
- }
|
||||||
|
- // 通知外部任务更新(如Adapter需要联动)
|
||||||
|
- if (mTaskUpdateListener != null) mTaskUpdateListener.onTaskUpdated(mPositionId, tasks);
|
||||||
|
- }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 4. addNewTask 方法:新增任务(同步服务+刷新列表)
|
4. - addNewTask 方法:新增任务(同步服务+刷新列表——复用后功能正常)
|
||||||
* 需在 PositionTaskListView 中添加:
|
- 需在 PositionTaskListView 中添加:
|
||||||
* public void addNewTask(PositionTaskModel newTask) {
|
- public void addNewTask(PositionTaskModel newTask) {
|
||||||
* if (newTask == null || TextUtils.isEmpty(newTask.getPositionId())) return;
|
- if (newTask == null || TextUtils.isEmpty(newTask.getPositionId())) return;
|
||||||
* MainService mainService = mMainServiceRef.get();
|
- MainService mainService = mMainServiceRef.get();
|
||||||
* if (mainService != null) {
|
- if (mainService != null) {
|
||||||
* mainService.addTask(newTask);
|
- mainService.addTask(newTask); // 同步到服务(确保数据持久化)
|
||||||
* syncTasksFromMainService(); // 新增后同步刷新
|
- syncTasksFromMainService(); // 新增后立即同步,刷新列表
|
||||||
* Toast.makeText(getContext(), "任务创建成功", Toast.LENGTH_SHORT).show();
|
- Toast.makeText(getContext(), "任务新增成功", Toast.LENGTH_SHORT).show();
|
||||||
* } else {
|
- } else {
|
||||||
* Toast.makeText(getContext(), "新增失败,请重试", Toast.LENGTH_SHORT).show();
|
- Toast.makeText(getContext(), "服务未就绪,新增失败", Toast.LENGTH_SHORT).show();
|
||||||
* }
|
- }
|
||||||
* }
|
- }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 5. clearData 方法:清空任务数据(释放资源)
|
5. - clearData 方法:清空任务数据(仅在Activity销毁时调用,不复用场景)
|
||||||
* 需在 PositionTaskListView 中添加:
|
- 需在 PositionTaskListView 中添加:
|
||||||
* public void clearData() {
|
- public void clearData() {
|
||||||
* if (mTaskList != null) mTaskList.clear(); // 清空任务列表数据
|
- if (mTaskList != null) mTaskList.clear(); // 清空本地任务列表
|
||||||
* if (mTaskAdapter != null) mTaskAdapter.notifyDataSetChanged(); // 刷新列表
|
- if (mTaskAdapter != null) mTaskAdapter.notifyDataSetChanged(); // 刷新空UI
|
||||||
* }
|
- }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 6. setOnTaskUpdatedListener 方法:设置任务更新回调
|
6. - setOnTaskUpdatedListener 方法:设置任务更新回调(复用后重新绑定,避免回调失效)
|
||||||
* 需在 PositionTaskListView 中添加:
|
- 需在 PositionTaskListView 中添加:
|
||||||
* public interface OnTaskUpdatedListener {
|
- public interface OnTaskUpdatedListener {
|
||||||
* void onTaskUpdated(String positionId, ArrayList<PositionTaskModel> updatedTasks);
|
- void onTaskUpdated(String positionId, ArrayList updatedTasks);
|
||||||
* }
|
- }
|
||||||
* private OnTaskUpdatedListener mTaskUpdateListener;
|
- private OnTaskUpdatedListener mTaskUpdateListener;
|
||||||
* public void setOnTaskUpdatedListener(OnTaskUpdatedListener listener) {
|
- public void setOnTaskUpdatedListener(OnTaskUpdatedListener listener) {
|
||||||
* this.mTaskUpdateListener = listener;
|
- this.mTaskUpdateListener = listener;
|
||||||
* }
|
- }
|
||||||
* // 任务变化时调用(如同步后/编辑后)
|
|
||||||
* private void notifyTaskUpdated(ArrayList<PositionTaskModel> updatedTasks) {
|
|
||||||
* if (mTaskUpdateListener != null) {
|
|
||||||
* mTaskUpdateListener.onTaskUpdated(mPositionId, updatedTasks);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user