任务触发响应模块已基本完成
This commit is contained in:
		| @@ -1,8 +1,8 @@ | |||||||
| #Created by .winboll/winboll_app_build.gradle | #Created by .winboll/winboll_app_build.gradle | ||||||
| #Tue Sep 30 06:43:35 GMT 2025 | #Tue Sep 30 08:01:34 GMT 2025 | ||||||
| stageCount=3 | stageCount=3 | ||||||
| libraryProject= | libraryProject= | ||||||
| baseVersion=15.0 | baseVersion=15.0 | ||||||
| publishVersion=15.0.2 | publishVersion=15.0.2 | ||||||
| buildCount=39 | buildCount=47 | ||||||
| baseBetaVersion=15.0.3 | baseBetaVersion=15.0.3 | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ 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 位置数据适配器(修复定时器:仅刷新实时距离,不干扰编辑中的任务) |  * @Describe 位置数据适配器(修复定时器:仅刷新实时距离,不干扰编辑中的任务;优化任务触发通知) | ||||||
|  */ |  */ | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
| import android.os.Handler; | import android.os.Handler; | ||||||
| @@ -42,7 +42,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     private static final String DEFAULT_TASK_DESC = "新位置任务"; |     private static final String DEFAULT_TASK_DESC = "新位置任务"; | ||||||
|     private static final int DEFAULT_TASK_DISTANCE = 100; |     private static final int DEFAULT_TASK_DISTANCE = 100; | ||||||
|  |  | ||||||
|     // 核心成员变量(新增:用于存储可见的距离TextView,避免遍历所有ViewHolder) |     // 核心成员变量(新增:1.位置ID→索引映射 2.主线程Handler 3.任务触发标记) | ||||||
|     private final ArrayList<PositionModel> mPositionList; |     private final ArrayList<PositionModel> mPositionList; | ||||||
|     private final ArrayList<PositionTaskModel> mAllPositionTasks; |     private final ArrayList<PositionTaskModel> mAllPositionTasks; | ||||||
|     private final Context mContext; |     private final Context mContext; | ||||||
| @@ -50,8 +50,11 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     private final Timer mDistanceTimer; |     private final Timer mDistanceTimer; | ||||||
|     private final Handler mMainHandler; |     private final Handler mMainHandler; | ||||||
|     private final Map<String, ArrayList<PositionTaskModel>> mPositionTaskMap; |     private final Map<String, ArrayList<PositionTaskModel>> mPositionTaskMap; | ||||||
|     // 关键新增:存储“位置ID → 距离TextView”的映射(仅包含当前可见的列表项) |  | ||||||
|     private final Map<String, TextView> mVisibleDistanceViews = new HashMap<>(); |     private final Map<String, TextView> mVisibleDistanceViews = new HashMap<>(); | ||||||
|  |     // 新增1:存储“位置ID→列表索引”映射(快速定位位置项,避免遍历) | ||||||
|  |     private final Map<String, Integer> mPositionIdToIndexMap = new HashMap<>(); | ||||||
|  |     // 新增2:主线程Handler(确保UI更新在主线程,避免异常) | ||||||
|  |     private final Handler mUiHandler = new Handler(Looper.getMainLooper()); | ||||||
|  |  | ||||||
|     // 接口回调(不变) |     // 接口回调(不变) | ||||||
|     public interface OnDeleteClickListener { |     public interface OnDeleteClickListener { | ||||||
| @@ -70,7 +73,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     private OnSavePositionClickListener mOnSavePositionClickListener; |     private OnSavePositionClickListener mOnSavePositionClickListener; | ||||||
|     private OnSavePositionTaskClickListener mOnSavePositionTaskClickListener; |     private OnSavePositionTaskClickListener mOnSavePositionTaskClickListener; | ||||||
|  |  | ||||||
|     // 构造函数(不变,仅定时器初始化逻辑修改) |     // 构造函数(新增:初始化位置ID→索引映射) | ||||||
|     public PositionAdapter(Context context, ArrayList<PositionModel> positionList, ArrayList<PositionTaskModel> allPositionTasks) { |     public PositionAdapter(Context context, ArrayList<PositionModel> positionList, ArrayList<PositionTaskModel> allPositionTasks) { | ||||||
|         this.mContext = context; |         this.mContext = context; | ||||||
|         this.mPositionList = (positionList != null) ? positionList : new ArrayList<PositionModel>(); |         this.mPositionList = (positionList != null) ? positionList : new ArrayList<PositionModel>(); | ||||||
| @@ -89,9 +92,11 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             mPositionTaskMap.put(validPosId, matchedTasks); |             mPositionTaskMap.put(validPosId, matchedTasks); | ||||||
|  |             // 新增:初始化“位置ID→索引”映射(索引即列表中的位置) | ||||||
|  |             mPositionIdToIndexMap.put(validPosId, mPositionList.indexOf(model)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 启动距离刷新定时器(核心修改:调用新的刷新逻辑) |         // 启动距离刷新定时器(不变) | ||||||
|         startDistanceRefreshTimer(); |         startDistanceRefreshTimer(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -119,28 +124,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|             mDistanceTimer.cancel(); |             mDistanceTimer.cancel(); | ||||||
|             mDistanceTimer.purge(); |             mDistanceTimer.purge(); | ||||||
|         } |         } | ||||||
|         // 清空可见距离视图缓存,避免内存泄漏 |  | ||||||
|         mVisibleDistanceViews.clear(); |         mVisibleDistanceViews.clear(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ---------------------- 核心修复1:定时器逻辑(仅刷新可见的距离TextView) ---------------------- |     // ---------------------- 核心修复1:定时器逻辑(仅刷新可见的距离TextView)(不变) ---------------------- | ||||||
|     /** |  | ||||||
|      * 启动实时距离刷新定时器(仅更新可见的距离文本,不刷新整个列表项) |  | ||||||
|      */ |  | ||||||
|     private void startDistanceRefreshTimer() { |     private void startDistanceRefreshTimer() { | ||||||
|         mDistanceTimer.scheduleAtFixedRate(new TimerTask() { |         mDistanceTimer.scheduleAtFixedRate(new TimerTask() { | ||||||
| 				@Override | 				@Override | ||||||
| 				public void run() { | 				public void run() { | ||||||
| 					// 切换到主线程(UI更新必须在主线程) |  | ||||||
| 					mMainHandler.post(new Runnable() { | 					mMainHandler.post(new Runnable() { | ||||||
| 							@Override | 							@Override | ||||||
| 							public void run() { | 							public void run() { | ||||||
| 								// 遍历所有可见的距离TextView,针对性更新(不触发列表项重新绑定) |  | ||||||
| 								for (Map.Entry<String, TextView> entry : mVisibleDistanceViews.entrySet()) { | 								for (Map.Entry<String, TextView> entry : mVisibleDistanceViews.entrySet()) { | ||||||
| 									String positionId = entry.getKey(); // 当前可见项的位置ID | 									String positionId = entry.getKey(); | ||||||
| 									TextView distanceView = entry.getValue(); // 要更新的距离文本控件 | 									TextView distanceView = entry.getValue(); | ||||||
|  |  | ||||||
| 									// 根据位置ID找到对应的PositionModel |  | ||||||
| 									PositionModel targetModel = null; | 									PositionModel targetModel = null; | ||||||
| 									for (PositionModel model : mPositionList) { | 									for (PositionModel model : mPositionList) { | ||||||
| 										if (positionId.equals(model.getPositionId())) { | 										if (positionId.equals(model.getPositionId())) { | ||||||
| @@ -149,7 +147,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 										} | 										} | ||||||
| 									} | 									} | ||||||
|  |  | ||||||
| 									// 若找到对应模型,直接更新距离文本(复用原有bindRealDistance逻辑) |  | ||||||
| 									if (targetModel != null) { | 									if (targetModel != null) { | ||||||
| 										bindRealDistance(distanceView, targetModel); | 										bindRealDistance(distanceView, targetModel); | ||||||
| 									} | 									} | ||||||
| @@ -157,13 +154,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 							} | 							} | ||||||
| 						}); | 						}); | ||||||
| 				} | 				} | ||||||
| 			}, 0, REFRESH_INTERVAL); // 0延迟启动,每5秒执行一次 | 			}, 0, REFRESH_INTERVAL); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ---------------------- 核心修复2:管理可见/不可见的距离TextView(避免内存泄漏+精准刷新) ---------------------- |     // ---------------------- 核心修复2:管理可见/不可见的距离TextView(不变) ---------------------- | ||||||
|     /** |  | ||||||
|      * 列表项变为“可见”时:将距离TextView加入缓存(供定时器刷新) |  | ||||||
|      */ |  | ||||||
|     @Override |     @Override | ||||||
|     public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { |     public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { | ||||||
|         super.onViewAttachedToWindow(holder); |         super.onViewAttachedToWindow(holder); | ||||||
| @@ -174,25 +168,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|  |  | ||||||
|         PositionModel model = mPositionList.get(position); |         PositionModel model = mPositionList.get(position); | ||||||
|         String positionId = model.getPositionId(); |         String positionId = model.getPositionId(); | ||||||
|         TextView distanceView = null; |         // 同步更新位置ID→索引映射(防止列表项位置变化导致索引失效) | ||||||
|  |         mPositionIdToIndexMap.put(positionId, position); | ||||||
|  |  | ||||||
|         // 根据视图类型,找到对应的距离TextView |         TextView distanceView = null; | ||||||
|         if (holder instanceof SimpleViewHolder) { |         if (holder instanceof SimpleViewHolder) { | ||||||
|             distanceView = ((SimpleViewHolder) holder).tvSimpleRealDistance; |             distanceView = ((SimpleViewHolder) holder).tvSimpleRealDistance; | ||||||
|         } else if (holder instanceof EditViewHolder) { |         } else if (holder instanceof EditViewHolder) { | ||||||
|             // 编辑视图若也显示距离(根据需求,若不显示可删除此分支) |  | ||||||
|             distanceView = ((EditViewHolder) holder).tvEditRealDistance; |             distanceView = ((EditViewHolder) holder).tvEditRealDistance; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 若距离TextView存在,加入缓存(key=位置ID,确保唯一) |  | ||||||
|         if (distanceView != null) { |         if (distanceView != null) { | ||||||
|             mVisibleDistanceViews.put(positionId, distanceView); |             mVisibleDistanceViews.put(positionId, distanceView); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 列表项变为“不可见”时:将距离TextView从缓存移除(避免内存泄漏+无效刷新) |  | ||||||
|      */ |  | ||||||
|     @Override |     @Override | ||||||
|     public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) { |     public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) { | ||||||
|         super.onViewDetachedFromWindow(holder); |         super.onViewDetachedFromWindow(holder); | ||||||
| @@ -203,14 +193,12 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|  |  | ||||||
|         PositionModel model = mPositionList.get(position); |         PositionModel model = mPositionList.get(position); | ||||||
|         String positionId = model.getPositionId(); |         String positionId = model.getPositionId(); | ||||||
|  |  | ||||||
|         // 从缓存移除不可见项的距离TextView |  | ||||||
|         if (mVisibleDistanceViews.containsKey(positionId)) { |         if (mVisibleDistanceViews.containsKey(positionId)) { | ||||||
|             mVisibleDistanceViews.remove(positionId); |             mVisibleDistanceViews.remove(positionId); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ---------------------- RecyclerView 核心方法(仅补充编辑视图的距离TextView绑定,其他不变) ---------------------- |     // ---------------------- RecyclerView 核心方法(不变) ---------------------- | ||||||
|     @Override |     @Override | ||||||
|     public int getItemViewType(int position) { |     public int getItemViewType(int position) { | ||||||
|         PositionModel model = mPositionList.get(position); |         PositionModel model = mPositionList.get(position); | ||||||
| @@ -233,6 +221,9 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|     @Override |     @Override | ||||||
|     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { |     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { | ||||||
|         PositionModel model = mPositionList.get(position); |         PositionModel model = mPositionList.get(position); | ||||||
|  |         // 同步更新位置ID→索引映射(确保索引与当前列表项位置一致) | ||||||
|  |         mPositionIdToIndexMap.put(model.getPositionId(), position); | ||||||
|  |  | ||||||
|         if (holder instanceof SimpleViewHolder) { |         if (holder instanceof SimpleViewHolder) { | ||||||
|             bindSimpleView((SimpleViewHolder) holder, model, position); |             bindSimpleView((SimpleViewHolder) holder, model, position); | ||||||
|         } else if (holder instanceof EditViewHolder) { |         } else if (holder instanceof EditViewHolder) { | ||||||
| @@ -245,18 +236,18 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|         return mPositionList.size(); |         return mPositionList.size(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // 回收ViewHolder时清理资源(不变,补充距离缓存移除) |     // 回收ViewHolder时清理资源(不变) | ||||||
|     @Override |     @Override | ||||||
|     public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { |     public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { | ||||||
|         super.onViewRecycled(holder); |         super.onViewRecycled(holder); | ||||||
|         // 移除缓存中已回收项的距离TextView |  | ||||||
|         int position = holder.getAdapterPosition(); |         int position = holder.getAdapterPosition(); | ||||||
|         if (position >= 0 && position < mPositionList.size()) { |         if (position >= 0 && position < mPositionList.size()) { | ||||||
|             String positionId = mPositionList.get(position).getPositionId(); |             String positionId = mPositionList.get(position).getPositionId(); | ||||||
|             mVisibleDistanceViews.remove(positionId); |             mVisibleDistanceViews.remove(positionId); | ||||||
|  |             // 移除已回收位置的索引映射(避免内存泄漏) | ||||||
|  |             mPositionIdToIndexMap.remove(positionId); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 清理任务列表资源(不变) |  | ||||||
|         if (holder instanceof SimpleViewHolder) { |         if (holder instanceof SimpleViewHolder) { | ||||||
|             ((SimpleViewHolder) holder).ptlvSimpleTasks.clearData(); |             ((SimpleViewHolder) holder).ptlvSimpleTasks.clearData(); | ||||||
|             ((SimpleViewHolder) holder).ptlvSimpleTasks.setOnTaskUpdatedListener(null); |             ((SimpleViewHolder) holder).ptlvSimpleTasks.setOnTaskUpdatedListener(null); | ||||||
| @@ -266,17 +257,13 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // 绑定简单视图(不变,仅确保距离TextView正确初始化) |     // 绑定简单视图(不变) | ||||||
|     private void bindSimpleView(final SimpleViewHolder holder, final PositionModel model, final int position) { |     private void bindSimpleView(final SimpleViewHolder holder, final PositionModel model, final int position) { | ||||||
|         // 1. 绑定位置基础信息(不变) |  | ||||||
|         holder.tvSimpleLongitude.setText(String.format("经度:%.6f", model.getLongitude())); |         holder.tvSimpleLongitude.setText(String.format("经度:%.6f", model.getLongitude())); | ||||||
|         holder.tvSimpleLatitude.setText(String.format("纬度:%.6f", model.getLatitude())); |         holder.tvSimpleLatitude.setText(String.format("纬度:%.6f", model.getLatitude())); | ||||||
|         holder.tvSimpleMemo.setText(String.format("备注:%s", model.getMemo())); |         holder.tvSimpleMemo.setText(String.format("备注:%s", model.getMemo())); | ||||||
|  |  | ||||||
|         // 2. 绑定实时距离(首次初始化时调用,后续由定时器刷新) |  | ||||||
|         bindRealDistance(holder.tvSimpleRealDistance, model); |         bindRealDistance(holder.tvSimpleRealDistance, model); | ||||||
|  |  | ||||||
|         // 3. 长按切换编辑视图(不变) |  | ||||||
|         holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { |         holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { | ||||||
| 				@Override | 				@Override | ||||||
| 				public boolean onLongClick(View v) { | 				public boolean onLongClick(View v) { | ||||||
| @@ -289,7 +276,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 							public boolean onMenuItemClick(MenuItem item) { | 							public boolean onMenuItemClick(MenuItem item) { | ||||||
| 								if (item.getItemId() == R.id.menu_edit) { | 								if (item.getItemId() == R.id.menu_edit) { | ||||||
| 									model.setIsSimpleView(false); | 									model.setIsSimpleView(false); | ||||||
| 									notifyItemChanged(position); // 仅切换视图时刷新,不影响定时器 | 									notifyItemChanged(position); | ||||||
| 									return true; | 									return true; | ||||||
| 								} | 								} | ||||||
| 								return false; | 								return false; | ||||||
| @@ -301,7 +288,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
|         // 4. 绑定任务列表(不变,确保编辑不被干扰) |  | ||||||
|         String currentPosId = model.getPositionId(); |         String currentPosId = model.getPositionId(); | ||||||
|         ArrayList<PositionTaskModel> matchedTasks = getSafeTasks(currentPosId); |         ArrayList<PositionTaskModel> matchedTasks = getSafeTasks(currentPosId); | ||||||
|         holder.ptlvSimpleTasks.clearData(); |         holder.ptlvSimpleTasks.clearData(); | ||||||
| @@ -311,30 +297,28 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // 绑定编辑视图(补充距离TextView绑定,其他不变) |     // 绑定编辑视图(不变) | ||||||
|     private void bindEditView(final EditViewHolder holder, final PositionModel model, final int position) { |     private void bindEditView(final EditViewHolder holder, final PositionModel model, final int position) { | ||||||
|         // 1. 绑定位置基础信息(新增:编辑视图的距离TextView初始化) |  | ||||||
|         holder.tvEditLongitude.setText(String.format("经度:%.6f", model.getLongitude())); |         holder.tvEditLongitude.setText(String.format("经度:%.6f", model.getLongitude())); | ||||||
|         holder.tvEditLatitude.setText(String.format("纬度:%.6f", model.getLatitude())); |         holder.tvEditLatitude.setText(String.format("纬度:%.6f", model.getLatitude())); | ||||||
|         holder.etEditMemo.setText(model.getMemo()); |         holder.etEditMemo.setText(model.getMemo()); | ||||||
|         holder.etEditMemo.setSelection(holder.etEditMemo.getText().length()); |         holder.etEditMemo.setSelection(holder.etEditMemo.getText().length()); | ||||||
|         // 新增:首次绑定编辑视图时,初始化距离文本(后续由定时器刷新) |  | ||||||
|         bindRealDistance(holder.tvEditRealDistance, model); |         bindRealDistance(holder.tvEditRealDistance, model); | ||||||
|  |  | ||||||
|         // 2. 绑定实时距离开关(不变) |  | ||||||
|         if (model.isEnableRealPositionDistance()) { |         if (model.isEnableRealPositionDistance()) { | ||||||
|             holder.rgRealDistanceSwitch.check(R.id.rb_enable); |             holder.rgRealDistanceSwitch.check(R.id.rb_enable); | ||||||
|         } else { |         } else { | ||||||
|             holder.rgRealDistanceSwitch.check(R.id.rb_disable); |             holder.rgRealDistanceSwitch.check(R.id.rb_disable); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 3. 绑定删除/取消/确定按钮(不变,确保任务编辑逻辑正常) |  | ||||||
|         holder.btnEditDelete.setOnClickListener(new View.OnClickListener() { |         holder.btnEditDelete.setOnClickListener(new View.OnClickListener() { | ||||||
| 				@Override | 				@Override | ||||||
| 				public void onClick(View v) { | 				public void onClick(View v) { | ||||||
| 					if (mOnDeleteClickListener != null) { | 					if (mOnDeleteClickListener != null) { | ||||||
| 						mOnDeleteClickListener.onDeleteClick(position); | 						mOnDeleteClickListener.onDeleteClick(position); | ||||||
| 						mPositionTaskMap.remove(model.getPositionId()); | 						mPositionTaskMap.remove(model.getPositionId()); | ||||||
|  | 						// 移除删除位置的索引映射 | ||||||
|  | 						mPositionIdToIndexMap.remove(model.getPositionId()); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
| @@ -376,7 +360,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
|         // 4. 绑定任务列表(不变,确保编辑中的任务不被刷新覆盖) |  | ||||||
|         final String currentPosId = model.getPositionId(); |         final String currentPosId = model.getPositionId(); | ||||||
|         ArrayList<PositionTaskModel> matchedTasks = getSafeTasks(currentPosId); |         ArrayList<PositionTaskModel> matchedTasks = getSafeTasks(currentPosId); | ||||||
|         holder.ptlvEditTasks.clearData(); |         holder.ptlvEditTasks.clearData(); | ||||||
| @@ -403,52 +386,51 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 					mAllPositionTasks.addAll(boundTasks); | 					mAllPositionTasks.addAll(boundTasks); | ||||||
|  |  | ||||||
| 					if (mOnSavePositionTaskClickListener != null) { | 					if (mOnSavePositionTaskClickListener != null) { | ||||||
|                         mOnSavePositionTaskClickListener.onSavePositionTaskClick(); | 						mOnSavePositionTaskClickListener.onSavePositionTaskClick(); | ||||||
|                     } | 					} | ||||||
|                     Toast.makeText(mContext, "任务信息已保存", Toast.LENGTH_SHORT).show(); | 					Toast.makeText(mContext, "任务信息已保存", Toast.LENGTH_SHORT).show(); | ||||||
|                 } | 				} | ||||||
|             }); | 			}); | ||||||
|  |  | ||||||
| 		if (holder.ptlvEditTasks.getAllTasks().isEmpty()) { |         if (holder.ptlvEditTasks.getAllTasks().isEmpty()) { | ||||||
| 			holder.ptlvEditTasks.init(matchedTasks, currentPosId); |             holder.ptlvEditTasks.init(matchedTasks, currentPosId); | ||||||
| 		} |         } | ||||||
| 		holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT); |         holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT); | ||||||
|  |  | ||||||
| 		// 5. 绑定新增任务按钮(不变) |         holder.btnAddTask.setOnClickListener(new View.OnClickListener() { | ||||||
| 		holder.btnAddTask.setOnClickListener(new View.OnClickListener() { | 				@Override | ||||||
|                 @Override | 				public void onClick(View v) { | ||||||
|                 public void onClick(View v) { | 					PositionTaskModel newTask = new PositionTaskModel( | ||||||
|                     PositionTaskModel newTask = new PositionTaskModel( |                         PositionTaskModel.genTaskId(), | ||||||
| 						PositionTaskModel.genTaskId(), |                         currentPosId, | ||||||
| 						currentPosId, |                         DEFAULT_TASK_DESC, | ||||||
| 						DEFAULT_TASK_DESC, |                         true, | ||||||
| 						true, |                         DEFAULT_TASK_DISTANCE, | ||||||
| 						DEFAULT_TASK_DISTANCE, |                         true | ||||||
| 						true | 					); | ||||||
|                     ); |  | ||||||
|  |  | ||||||
|                     ArrayList<PositionTaskModel> currentTasks = getSafeTasks(currentPosId); | 					ArrayList<PositionTaskModel> currentTasks = getSafeTasks(currentPosId); | ||||||
|                     currentTasks.add(newTask); | 					currentTasks.add(newTask); | ||||||
|                     mPositionTaskMap.put(currentPosId, new ArrayList<PositionTaskModel>(currentTasks)); | 					mPositionTaskMap.put(currentPosId, new ArrayList<PositionTaskModel>(currentTasks)); | ||||||
|                     mAllPositionTasks.add(newTask); | 					mAllPositionTasks.add(newTask); | ||||||
|  |  | ||||||
|                     holder.ptlvEditTasks.clearData(); | 					holder.ptlvEditTasks.clearData(); | ||||||
|                     holder.ptlvEditTasks.init(currentTasks, currentPosId); | 					holder.ptlvEditTasks.init(currentTasks, currentPosId); | ||||||
|                     holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT); | 					holder.ptlvEditTasks.setViewStatus(PositionTaskListView.VIEW_MODE_EDIT); | ||||||
|                     Toast.makeText(mContext, "已新增1个任务(绑定当前位置)", Toast.LENGTH_SHORT).show(); | 					Toast.makeText(mContext, "已新增1个任务(绑定当前位置)", Toast.LENGTH_SHORT).show(); | ||||||
|                 } | 				} | ||||||
|             }); | 			}); | ||||||
| 	} |     } | ||||||
|  |  | ||||||
| 	// 工具方法:绑定实时距离(逻辑不变,仅负责文本更新,不影响其他控件) |     // 工具方法:绑定实时距离(不变) | ||||||
| 	private void bindRealDistance(TextView distanceView, PositionModel model) { |     private void bindRealDistance(TextView distanceView, PositionModel model) { | ||||||
| 		if (!model.isEnableRealPositionDistance()) { |         if (!model.isEnableRealPositionDistance()) { | ||||||
| 			distanceView.setText("实时距离:未启用"); |             distanceView.setText("实时距离:未启用"); | ||||||
| 			distanceView.setTextColor(mContext.getResources().getColor(R.color.colorGrayText)); |             distanceView.setTextColor(mContext.getResources().getColor(R.color.colorGrayText)); | ||||||
| 			return; |             return; | ||||||
| 		} |         } | ||||||
|  |  | ||||||
| 		if (mCurrentGpsPosition == null) { |         if (mCurrentGpsPosition == null) { | ||||||
| 			distanceView.setText("实时距离:等待GPS定位"); | 			distanceView.setText("实时距离:等待GPS定位"); | ||||||
| 			distanceView.setTextColor(mContext.getResources().getColor(R.color.colorGrayText)); | 			distanceView.setTextColor(mContext.getResources().getColor(R.color.colorGrayText)); | ||||||
| 			return; | 			return; | ||||||
| @@ -456,6 +438,8 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
|  |  | ||||||
| 		try { | 		try { | ||||||
| 			double distanceM = PositionModel.calculatePositionDistance(mCurrentGpsPosition, model, false); | 			double distanceM = PositionModel.calculatePositionDistance(mCurrentGpsPosition, model, false); | ||||||
|  | // 设置任务列表触发状态(调用优化后的通知逻辑) | ||||||
|  | 			bingoTask(model, (int) distanceM); | ||||||
| 			String distanceText = (distanceM < 1000) ? | 			String distanceText = (distanceM < 1000) ? | ||||||
| 				String.format("实时距离:%.1f 米", distanceM) : | 				String.format("实时距离:%.1f 米", distanceM) : | ||||||
| 				String.format("实时距离:%.1f 千米", distanceM / 1000); | 				String.format("实时距离:%.1f 千米", distanceM / 1000); | ||||||
| @@ -467,38 +451,96 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 工具方法:安全获取任务列表(不变) | // ---------------------- 核心优化:bingoTask 任务触发通知逻辑(替换 notifyDataSetChanged()) ---------------------- | ||||||
| 	private ArrayList<PositionTaskModel> getSafeTasks(String positionId) { | 	private void bingoTask(PositionModel model, int distanceM) { | ||||||
|  | // 1. 标记是否有任务触发(避免无变化时无效更新) | ||||||
|  | 		boolean hasTaskTriggered = false; | ||||||
|  | // 2. 记录当前位置ID(后续精准定位列表项) | ||||||
|  | 		final String targetPosId = model.getPositionId(); | ||||||
|  |  | ||||||
|  | // 遍历当前位置的任务,判断是否触发 | ||||||
|  | 		for (PositionTaskModel task : mAllPositionTasks) { | ||||||
|  | 			if (targetPosId.equals(task.getPositionId())) { | ||||||
|  | // 暂存旧状态(避免重复触发更新) | ||||||
|  | 				boolean oldBingoState = task.isBingo(); | ||||||
|  | 				boolean newBingoState = false; | ||||||
|  |  | ||||||
|  | // 根据任务条件判断新触发状态 | ||||||
|  | 				if (task.isGreaterThan()) { | ||||||
|  | 					newBingoState = distanceM > task.getDiscussDistance(); | ||||||
|  | 				} else if (task.isLessThan()) { | ||||||
|  | 					newBingoState = distanceM < task.getDiscussDistance(); | ||||||
|  | 				} else { | ||||||
|  | 					newBingoState = true; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | // 仅当状态变化时,才更新任务状态并标记需要通知 | ||||||
|  | 				if (newBingoState != oldBingoState) { | ||||||
|  | 					task.setIsBingo(newBingoState); | ||||||
|  | 					hasTaskTriggered = true; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | // 3. 仅当有任务触发且状态变化时,才执行精准更新(避免全局刷新) | ||||||
|  | 		if (hasTaskTriggered) { | ||||||
|  | // 切换到主线程更新UI(解决子线程更新异常) | ||||||
|  | 			mUiHandler.post(new Runnable() { | ||||||
|  | 					@Override | ||||||
|  | 					public void run() { | ||||||
|  | // 从映射表快速获取位置索引(避免遍历列表,提升效率) | ||||||
|  | 						Integer targetPosIndex = mPositionIdToIndexMap.get(targetPosId); | ||||||
|  | 						if (targetPosIndex != null && targetPosIndex >= 0 && targetPosIndex < mPositionList.size()) { | ||||||
|  | // 精准更新单个位置项(仅刷新该位置的任务列表,不干扰其他项) | ||||||
|  | 							notifyItemChanged(targetPosIndex); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | // 工具方法:安全获取任务列表(不变) | ||||||
|  | 	private ArrayList getSafeTasks(String positionId) { | ||||||
| 		if (!mPositionTaskMap.containsKey(positionId)) { | 		if (!mPositionTaskMap.containsKey(positionId)) { | ||||||
| 			mPositionTaskMap.put(positionId, new ArrayList<PositionTaskModel>()); | 			mPositionTaskMap.put(positionId, new ArrayList()); | ||||||
| 		} | 		} | ||||||
| 		return mPositionTaskMap.get(positionId); | 		return mPositionTaskMap.get(positionId); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 对外API:新增位置(不变) | // 对外API:新增位置(补充索引映射更新) | ||||||
| 	public void addPosition(PositionModel model) { | 	public void addPosition(PositionModel model) { | ||||||
| 		if (model == null) return; | 		if (model == null) return; | ||||||
| 		String validPosId = model.getPositionId(); | 		String validPosId = model.getPositionId(); | ||||||
| 		mPositionList.add(model); | 		mPositionList.add(model); | ||||||
|  | // 新增:添加新位置的索引映射(索引为列表最后一位) | ||||||
|  | 		mPositionIdToIndexMap.put(validPosId, mPositionList.size() - 1); | ||||||
|  |  | ||||||
| 		if (!mPositionTaskMap.containsKey(validPosId)) { | 		if (!mPositionTaskMap.containsKey(validPosId)) { | ||||||
| 			mPositionTaskMap.put(validPosId, new ArrayList<PositionTaskModel>()); | 			mPositionTaskMap.put(validPosId, new ArrayList()); | ||||||
| 		} | 		} | ||||||
| 		notifyItemInserted(mPositionList.size() - 1); | 		notifyItemInserted(mPositionList.size() - 1); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 对外API:删除位置(不变,补充距离缓存清理) | // 对外API:删除位置(补充索引映射清理) | ||||||
| 	public void removePosition(int position) { | 	public void removePosition(int position) { | ||||||
| 		if (position < 0 || position >= mPositionList.size()) return; | 		if (position < 0 || position >= mPositionList.size()) return; | ||||||
| 		PositionModel removedModel = mPositionList.get(position); | 		PositionModel removedModel = mPositionList.get(position); | ||||||
| 		String removedPosId = removedModel.getPositionId(); | 		String removedPosId = removedModel.getPositionId(); | ||||||
|  |  | ||||||
| 		// 1. 清理距离缓存(新增:移除已删除位置的距离TextView) | // 1. 清理距离缓存和索引映射(新增) | ||||||
| 		mVisibleDistanceViews.remove(removedPosId); | 		mVisibleDistanceViews.remove(removedPosId); | ||||||
|  | 		mPositionIdToIndexMap.remove(removedPosId); | ||||||
|  |  | ||||||
| 		// 2. 清理全局任务列表和映射表(不变) | // 2. 重新同步剩余位置的索引映射(避免删除后索引错位) | ||||||
| 		Iterator<PositionTaskModel> taskIterator = mAllPositionTasks.iterator(); | 		for (int i = position; i < mPositionList.size(); i++) { | ||||||
|  | 			PositionModel remainingModel = mPositionList.get(i); | ||||||
|  | 			mPositionIdToIndexMap.put(remainingModel.getPositionId(), i); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | // 3. 清理全局任务列表和映射表(不变) | ||||||
|  | 		Iterator taskIterator = mAllPositionTasks.iterator(); | ||||||
| 		while (taskIterator.hasNext()) { | 		while (taskIterator.hasNext()) { | ||||||
| 			PositionTaskModel task = taskIterator.next(); | 			PositionTaskModel task = (PositionTaskModel)taskIterator.next(); | ||||||
| 			if (task != null && removedPosId.equals(task.getPositionId())) { | 			if (task != null && removedPosId.equals(task.getPositionId())) { | ||||||
| 				taskIterator.remove(); | 				taskIterator.remove(); | ||||||
| 			} | 			} | ||||||
| @@ -510,16 +552,16 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 		notifyItemRangeChanged(position, mPositionList.size()); | 		notifyItemRangeChanged(position, mPositionList.size()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 对外API:更新所有位置(不变,补充距离缓存同步) | // 对外API:更新所有位置(补充索引映射同步) | ||||||
| 	public void updateAllPositions(ArrayList<PositionModel> newPositionList) { | 	public void updateAllPositions(ArrayList<PositionModel> newPositionList) { | ||||||
| 		if (newPositionList == null) return; | 		if (newPositionList == null) return; | ||||||
| 		mPositionList.clear(); | 		mPositionList.clear(); | ||||||
| 		mPositionList.addAll(newPositionList); | 		mPositionList.addAll(newPositionList); | ||||||
|  |  | ||||||
| 		// 1. 清理距离缓存中无效的位置ID(新增:仅保留新列表中的位置) | // 1. 清理距离缓存中无效的位置ID(不变) | ||||||
| 		Iterator<String> distanceViewIter = mVisibleDistanceViews.keySet().iterator(); | 		Iterator distanceViewIter = mVisibleDistanceViews.keySet().iterator(); | ||||||
| 		while (distanceViewIter.hasNext()) { | 		while (distanceViewIter.hasNext()) { | ||||||
| 			String posId = distanceViewIter.next(); | 			String posId = (String)distanceViewIter.next(); | ||||||
| 			boolean isPosExist = false; | 			boolean isPosExist = false; | ||||||
| 			for (PositionModel model : newPositionList) { | 			for (PositionModel model : newPositionList) { | ||||||
| 				if (posId.equals(model.getPositionId())) { | 				if (posId.equals(model.getPositionId())) { | ||||||
| @@ -532,10 +574,10 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// 2. 清理任务映射表(不变) | // 2. 清理任务映射表(不变) | ||||||
| 		Iterator<String> taskMapKeyIter = mPositionTaskMap.keySet().iterator(); | 		Iterator taskMapKeyIter = mPositionTaskMap.keySet().iterator(); | ||||||
| 		while (taskMapKeyIter.hasNext()) { | 		while (taskMapKeyIter.hasNext()) { | ||||||
| 			String posId = taskMapKeyIter.next(); | 			String posId = (String)taskMapKeyIter.next(); | ||||||
| 			boolean isPosExist = false; | 			boolean isPosExist = false; | ||||||
| 			for (PositionModel model : newPositionList) { | 			for (PositionModel model : newPositionList) { | ||||||
| 				if (posId.equals(model.getPositionId())) { | 				if (posId.equals(model.getPositionId())) { | ||||||
| @@ -548,18 +590,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// 3. 为新位置初始化任务列表(不变) | // 3. 重新初始化索引映射和任务列表(新增索引同步) | ||||||
| 		for (PositionModel model : newPositionList) { | 		mPositionIdToIndexMap.clear(); | ||||||
|  | 		for (int i = 0; i < newPositionList.size(); i++) { | ||||||
|  | 			PositionModel model = (PositionModel)newPositionList.get(i); | ||||||
| 			String posId = model.getPositionId(); | 			String posId = model.getPositionId(); | ||||||
|  | 			mPositionIdToIndexMap.put(posId, i); // 同步新列表的索引 | ||||||
| 			if (!mPositionTaskMap.containsKey(posId)) { | 			if (!mPositionTaskMap.containsKey(posId)) { | ||||||
| 				mPositionTaskMap.put(posId, new ArrayList<PositionTaskModel>()); | 				mPositionTaskMap.put(posId, new ArrayList()); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		notifyDataSetChanged(); | 		notifyDataSetChanged(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 对外API:批量切换简单视图(不变) | // 对外API:批量切换简单视图(不变) | ||||||
| 	public void switchAllToSimpleView() { | 	public void switchAllToSimpleView() { | ||||||
| 		for (PositionModel model : mPositionList) { | 		for (PositionModel model : mPositionList) { | ||||||
| 			model.setIsSimpleView(true); | 			model.setIsSimpleView(true); | ||||||
| @@ -567,18 +612,17 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 		notifyDataSetChanged(); | 		notifyDataSetChanged(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 对外API:获取位置列表(不变) | // 对外API:获取位置列表(不变) | ||||||
| 	public ArrayList<PositionModel> getPositionList() { | 	public ArrayList getPositionList() { | ||||||
| 		return new ArrayList<PositionModel>(mPositionList); | 		return new ArrayList(mPositionList); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// ---------------------- ViewHolder 定义(核心补充:编辑视图的距离TextView) ---------------------- | // ---------------------- ViewHolder 定义(不变) ---------------------- | ||||||
| 	// 简单视图Holder(不变) |  | ||||||
| 	public static class SimpleViewHolder extends RecyclerView.ViewHolder { | 	public static class SimpleViewHolder extends RecyclerView.ViewHolder { | ||||||
| 		TextView tvSimpleLongitude; | 		TextView tvSimpleLongitude; | ||||||
| 		TextView tvSimpleLatitude; | 		TextView tvSimpleLatitude; | ||||||
| 		TextView tvSimpleMemo; | 		TextView tvSimpleMemo; | ||||||
| 		TextView tvSimpleRealDistance; // 简单视图-距离文本 | 		TextView tvSimpleRealDistance; | ||||||
| 		PositionTaskListView ptlvSimpleTasks; | 		PositionTaskListView ptlvSimpleTasks; | ||||||
|  |  | ||||||
| 		public SimpleViewHolder(@NonNull View itemView) { | 		public SimpleViewHolder(@NonNull View itemView) { | ||||||
| @@ -591,7 +635,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// 编辑视图Holder(核心补充:tvEditRealDistance 距离文本控件) |  | ||||||
| 	public static class EditViewHolder extends RecyclerView.ViewHolder { | 	public static class EditViewHolder extends RecyclerView.ViewHolder { | ||||||
| 		TextView tvEditLongitude; | 		TextView tvEditLongitude; | ||||||
| 		TextView tvEditLatitude; | 		TextView tvEditLatitude; | ||||||
| @@ -604,7 +647,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 		Button btnEditConfirm; | 		Button btnEditConfirm; | ||||||
| 		PositionTaskListView ptlvEditTasks; | 		PositionTaskListView ptlvEditTasks; | ||||||
| 		Button btnAddTask; | 		Button btnAddTask; | ||||||
| 		TextView tvEditRealDistance; // 新增:编辑视图-距离文本(与布局文件对应) | 		TextView tvEditRealDistance; | ||||||
|  |  | ||||||
| 		public EditViewHolder(@NonNull View itemView) { | 		public EditViewHolder(@NonNull View itemView) { | ||||||
| 			super(itemView); | 			super(itemView); | ||||||
| @@ -619,9 +662,8 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | |||||||
| 			btnEditConfirm = (Button) itemView.findViewById(R.id.btn_edit_confirm); | 			btnEditConfirm = (Button) itemView.findViewById(R.id.btn_edit_confirm); | ||||||
| 			ptlvEditTasks = (PositionTaskListView) itemView.findViewById(R.id.ptlv_edit_tasks); | 			ptlvEditTasks = (PositionTaskListView) itemView.findViewById(R.id.ptlv_edit_tasks); | ||||||
| 			btnAddTask = (Button) itemView.findViewById(R.id.btn_add_task); | 			btnAddTask = (Button) itemView.findViewById(R.id.btn_add_task); | ||||||
| 			tvEditRealDistance = (TextView) itemView.findViewById(R.id.tv_edit_real_distance); // 绑定编辑视图的距离控件 | 			tvEditRealDistance = (TextView) itemView.findViewById(R.id.tv_edit_real_distance); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -26,6 +26,8 @@ public class PositionTaskModel extends BaseBean { | |||||||
| 	boolean isLessThan; | 	boolean isLessThan; | ||||||
| 	// 任务条件距离(单位:米) | 	// 任务条件距离(单位:米) | ||||||
| 	int discussDistance; | 	int discussDistance; | ||||||
|  | 	// 任务是否已触发 | ||||||
|  | 	boolean isBingo = false; | ||||||
| 	// 是否启用任务 | 	// 是否启用任务 | ||||||
| 	boolean isEnable; | 	boolean isEnable; | ||||||
|  |  | ||||||
| @@ -51,6 +53,14 @@ public class PositionTaskModel extends BaseBean { | |||||||
| 		this.isEnable = true; | 		this.isEnable = true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public void setIsBingo(boolean isBingo) { | ||||||
|  | 		this.isBingo = isBingo; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public boolean isBingo() { | ||||||
|  | 		return isBingo; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// ---------------------- Getter/Setter(确保positionId不为空,距离有效) ---------------------- | 	// ---------------------- Getter/Setter(确保positionId不为空,距离有效) ---------------------- | ||||||
| 	public void setTaskId(String taskId) { | 	public void setTaskId(String taskId) { | ||||||
| 		this.taskId = (taskId == null || taskId.trim().isEmpty()) ? genTaskId() : taskId; | 		this.taskId = (taskId == null || taskId.trim().isEmpty()) ? genTaskId() : taskId; | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package cc.winboll.studio.positions.views; | |||||||
| /** | /** | ||||||
|  * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> |  * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> | ||||||
|  * @Date 2025/09/30 08:09 |  * @Date 2025/09/30 08:09 | ||||||
|  * @Describe 位置任务列表视图(支持简单/编辑模式,确保任务修改实时生效) |  * @Describe 位置任务列表视图(支持简单/编辑模式,含 isBingo 红点标识) | ||||||
|  */ |  */ | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
| import android.util.AttributeSet; | import android.util.AttributeSet; | ||||||
| @@ -65,29 +65,21 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|     // 初始化视图(绑定控件+设置布局) |     // 初始化视图(绑定控件+设置布局) | ||||||
|     private void initView(Context context) { |     private void initView(Context context) { | ||||||
|         setOrientation(VERTICAL); |         setOrientation(VERTICAL); | ||||||
|         // 加载根布局(view_position_task_list.xml) |  | ||||||
|         LayoutInflater.from(context).inflate(R.layout.view_position_task_list, this, true); |         LayoutInflater.from(context).inflate(R.layout.view_position_task_list, this, true); | ||||||
|  |  | ||||||
|         // 绑定RecyclerView并设置布局管理器 |  | ||||||
|         mRvTasks = (RecyclerView) findViewById(R.id.rv_position_tasks); |         mRvTasks = (RecyclerView) findViewById(R.id.rv_position_tasks); | ||||||
|         mRvTasks.setLayoutManager(new LinearLayoutManager(context)); |         mRvTasks.setLayoutManager(new LinearLayoutManager(context)); | ||||||
|  |  | ||||||
|         // 初始化任务列表+适配器(强引用关联,确保数据同步) |  | ||||||
|         mTaskList = new ArrayList<PositionTaskModel>(); |         mTaskList = new ArrayList<PositionTaskModel>(); | ||||||
|         mTaskAdapter = new TaskListAdapter(mTaskList); |         mTaskAdapter = new TaskListAdapter(mTaskList); | ||||||
|         mRvTasks.setAdapter(mTaskAdapter); |         mRvTasks.setAdapter(mTaskAdapter); | ||||||
|  |  | ||||||
|         // 默认简单模式 |  | ||||||
|         mCurrentViewMode = VIEW_MODE_SIMPLE; |         mCurrentViewMode = VIEW_MODE_SIMPLE; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ---------------------- 对外API ---------------------- |     // ---------------------- 对外API ---------------------- | ||||||
|     /** |  | ||||||
|      * 初始化任务列表(仅首次空列表时加载,避免覆盖修改后数据) |  | ||||||
|      */ |  | ||||||
|     public void init(ArrayList<PositionTaskModel> taskList, String positionId) { |     public void init(ArrayList<PositionTaskModel> taskList, String positionId) { | ||||||
|         this.mBindPositionId = positionId; |         this.mBindPositionId = positionId; | ||||||
|         // 仅内部列表为空时加载外部数据 |  | ||||||
|         if (this.mTaskList.isEmpty()) { |         if (this.mTaskList.isEmpty()) { | ||||||
|             ArrayList<PositionTaskModel> matchedTasks = new ArrayList<PositionTaskModel>(); |             ArrayList<PositionTaskModel> matchedTasks = new ArrayList<PositionTaskModel>(); | ||||||
|             if (taskList != null && !taskList.isEmpty()) { |             if (taskList != null && !taskList.isEmpty()) { | ||||||
| @@ -103,9 +95,6 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|         mTaskAdapter.notifyDataSetChanged(); |         mTaskAdapter.notifyDataSetChanged(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 设置视图模式(简单/编辑) |  | ||||||
|      */ |  | ||||||
|     public void setViewStatus(int viewMode) { |     public void setViewStatus(int viewMode) { | ||||||
|         if (viewMode != VIEW_MODE_SIMPLE && viewMode != VIEW_MODE_EDIT) { |         if (viewMode != VIEW_MODE_SIMPLE && viewMode != VIEW_MODE_EDIT) { | ||||||
|             return; |             return; | ||||||
| @@ -114,23 +103,14 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|         mTaskAdapter.notifyDataSetChanged(); |         mTaskAdapter.notifyDataSetChanged(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 设置任务修改回调 |  | ||||||
|      */ |  | ||||||
|     public void setOnTaskUpdatedListener(OnTaskUpdatedListener listener) { |     public void setOnTaskUpdatedListener(OnTaskUpdatedListener listener) { | ||||||
|         this.mOnTaskUpdatedListener = listener; |         this.mOnTaskUpdatedListener = listener; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 获取当前任务列表(返回副本,避免外部修改污染) |  | ||||||
|      */ |  | ||||||
|     public ArrayList<PositionTaskModel> getAllTasks() { |     public ArrayList<PositionTaskModel> getAllTasks() { | ||||||
|         return new ArrayList<PositionTaskModel>(mTaskList); |         return new ArrayList<PositionTaskModel>(mTaskList); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 清空任务数据(避免RecyclerView复用残留) |  | ||||||
|      */ |  | ||||||
|     public void clearData() { |     public void clearData() { | ||||||
|         mTaskList.clear(); |         mTaskList.clear(); | ||||||
|         if (mTaskAdapter != null && mTaskAdapter.mData != null) { |         if (mTaskAdapter != null && mTaskAdapter.mData != null) { | ||||||
| @@ -140,9 +120,6 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|         mBindPositionId = null; |         mBindPositionId = null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 主动触发任务同步(供外部强制同步数据) |  | ||||||
|      */ |  | ||||||
|     public void triggerTaskSync() { |     public void triggerTaskSync() { | ||||||
|         if (mOnTaskUpdatedListener != null && mBindPositionId != null) { |         if (mOnTaskUpdatedListener != null && mBindPositionId != null) { | ||||||
|             mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mTaskList)); |             mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mTaskList)); | ||||||
| @@ -150,9 +127,6 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ---------------------- 内部工具方法 ---------------------- |     // ---------------------- 内部工具方法 ---------------------- | ||||||
|     /** |  | ||||||
|      * 校验任务是否与当前位置匹配 |  | ||||||
|      */ |  | ||||||
|     private boolean isTaskMatchedWithPosition(PositionTaskModel task) { |     private boolean isTaskMatchedWithPosition(PositionTaskModel task) { | ||||||
|         if (task == null || mBindPositionId == null || mBindPositionId.trim().isEmpty()) { |         if (task == null || mBindPositionId == null || mBindPositionId.trim().isEmpty()) { | ||||||
|             return false; |             return false; | ||||||
| @@ -160,53 +134,63 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|         return mBindPositionId.equals(task.getPositionId()); |         return mBindPositionId.equals(task.getPositionId()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ---------------------- 内部Adapter:任务列表适配器(核心修改:确保修改生效) ---------------------- |     // ---------------------- 内部Adapter:适配 isBingo 红点(核心调整) ---------------------- | ||||||
|     private class TaskListAdapter extends RecyclerView.Adapter<TaskListAdapter.TaskViewHolder> { |     private class TaskListAdapter extends RecyclerView.Adapter<TaskListAdapter.TaskViewHolder> { | ||||||
|         // 适配器数据源(与外部mTaskList强引用,确保数据实时同步) |  | ||||||
|         private final List<PositionTaskModel> mData; |         private final List<PositionTaskModel> mData; | ||||||
|  |  | ||||||
|         public TaskListAdapter(List<PositionTaskModel> data) { |         public TaskListAdapter(List<PositionTaskModel> data) { | ||||||
|             this.mData = data; |             this.mData = data; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 获取列表项数量(空列表显示1个“空提示”项) |  | ||||||
|         @Override |         @Override | ||||||
|         public int getItemCount() { |         public int getItemCount() { | ||||||
|             return mData.isEmpty() ? 1 : mData.size(); |             return mData.isEmpty() ? 1 : mData.size(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 区分视图类型(0=空提示,1=任务项) |         // 调整:根据“是否空列表”+“视图模式”区分视图类型(确保简单/编辑模式加载对应布局) | ||||||
|         @Override |         @Override | ||||||
|         public int getItemViewType(int position) { |         public int getItemViewType(int position) { | ||||||
|             return mData.isEmpty() ? 0 : 1; |             if (mData.isEmpty()) { | ||||||
|  |                 return 0; // 0=空提示 | ||||||
|  |             } else { | ||||||
|  |                 return mCurrentViewMode; // 1=简单模式,2=编辑模式(复用视图模式常量) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 创建ViewHolder |         // 调整:按视图类型加载布局(简单模式加载带红点的布局,编辑模式加载原有布局) | ||||||
|         @NonNull |         @NonNull | ||||||
|         @Override |         @Override | ||||||
|         public TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |         public TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||||||
|             Context context = parent.getContext(); |             Context context = parent.getContext(); | ||||||
|             LayoutInflater inflater = LayoutInflater.from(context); |             LayoutInflater inflater = LayoutInflater.from(context); | ||||||
|  |  | ||||||
|             if (viewType == 0) { |             if (viewType == 0) { | ||||||
|                 // 空提示布局(item_task_empty.xml) |                 // 空提示布局 | ||||||
|                 View emptyView = inflater.inflate(R.layout.item_task_empty, parent, false); |                 View emptyView = inflater.inflate(R.layout.item_task_empty, parent, false); | ||||||
|                 return new EmptyViewHolder(emptyView); |                 return new EmptyViewHolder(emptyView); | ||||||
|  |             } else if (viewType == VIEW_MODE_SIMPLE) { | ||||||
|  |                 // 简单模式布局(带 isBingo 红点) | ||||||
|  |                 View simpleTaskView = inflater.inflate(R.layout.item_position_task_simple, parent, false); | ||||||
|  |                 return new SimpleTaskViewHolder(simpleTaskView); | ||||||
|             } else { |             } else { | ||||||
|                 // 任务项布局(item_task_content.xml) |                 // 编辑模式布局(原有布局不变) | ||||||
|                 View taskView = inflater.inflate(R.layout.item_task_content, parent, false); |                 View editTaskView = inflater.inflate(R.layout.item_task_content, parent, false); | ||||||
|                 return new TaskContentViewHolder(taskView); |                 return new TaskContentViewHolder(editTaskView); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 绑定数据(核心:修复开关监听重复绑定+实时刷新) |         // 调整:按视图类型绑定数据(简单模式绑定红点+文本,编辑模式绑定原有逻辑) | ||||||
|         @Override |         @Override | ||||||
|         public void onBindViewHolder(@NonNull TaskViewHolder holder, int position) { |         public void onBindViewHolder(@NonNull TaskViewHolder holder, int position) { | ||||||
|  |             // 空提示处理(不变) | ||||||
|             if (holder instanceof EmptyViewHolder) { |             if (holder instanceof EmptyViewHolder) { | ||||||
|                 // 空提示项无需绑定数据 |                 EmptyViewHolder emptyHolder = (EmptyViewHolder) holder; | ||||||
|  |                 TextView tvEmptyTip = (TextView) emptyHolder.itemView.findViewById(R.id.tv_task_empty_tip); | ||||||
|  |                 tvEmptyTip.setText(mCurrentViewMode == VIEW_MODE_EDIT ? "暂无任务,点击\"添加新任务\"创建" : "暂无启用的任务"); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // 校验位置有效性(避免越界) |             // 任务项有效性校验(不变) | ||||||
|             if (position >= mData.size()) { |             if (position >= mData.size()) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @@ -215,16 +199,28 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // 绑定任务数据 |             // 简单模式:绑定红点(isBingo)和文本数据 | ||||||
|             final TaskContentViewHolder contentHolder = (TaskContentViewHolder) holder; |             if (holder instanceof SimpleTaskViewHolder) { | ||||||
|             bindTaskData(contentHolder, task, position); |                 SimpleTaskViewHolder simpleHolder = (SimpleTaskViewHolder) holder; | ||||||
|  |                 // 绑定任务描述 | ||||||
|  |                 simpleHolder.tvSimpleTaskDesc.setText(String.format("任务:%s", task.getTaskDescription())); | ||||||
|  |                 // 绑定距离条件 | ||||||
|  |                 String distanceCond = task.isGreaterThan() ? "大于" : "小于"; | ||||||
|  |                 simpleHolder.tvSimpleDistanceCond.setText(String.format("条件:距离 %s %d 米", distanceCond, task.getDiscussDistance())); | ||||||
|  |                 // 绑定启用状态 | ||||||
|  |                 simpleHolder.tvSimpleIsEnable.setText(task.isEnable() ? "状态:已启用" : "状态:已禁用"); | ||||||
|  |                 // 核心:根据 isBingo 控制红点显示(true=显示,false=隐藏) | ||||||
|  |                 simpleHolder.vBingoDot.setVisibility(task.isBingo() ? View.VISIBLE : View.GONE); | ||||||
|  |             } | ||||||
|  |             // 编辑模式:沿用原有绑定逻辑(不变) | ||||||
|  |             else if (holder instanceof TaskContentViewHolder) { | ||||||
|  |                 TaskContentViewHolder contentHolder = (TaskContentViewHolder) holder; | ||||||
|  |                 bindTaskData(contentHolder, task, position); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /** |         // ---------------------- 原有编辑模式绑定逻辑(完全不变) ---------------------- | ||||||
|          * 绑定任务具体数据(核心修复:开关监听去重+修改后实时刷新) |  | ||||||
|          */ |  | ||||||
|         private void bindTaskData(final TaskContentViewHolder holder, final PositionTaskModel task, final int position) { |         private void bindTaskData(final TaskContentViewHolder holder, final PositionTaskModel task, final int position) { | ||||||
|             // 1. 绑定基础信息(描述、距离条件、启用状态) |  | ||||||
|             String taskDesc = (task.getTaskDescription() == null) ? "未设置描述" : task.getTaskDescription(); |             String taskDesc = (task.getTaskDescription() == null) ? "未设置描述" : task.getTaskDescription(); | ||||||
|             holder.tvTaskDesc.setText(String.format("任务:%s", taskDesc)); |             holder.tvTaskDesc.setText(String.format("任务:%s", taskDesc)); | ||||||
|  |  | ||||||
| @@ -232,21 +228,18 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|             holder.tvTaskDistance.setText(String.format("条件:%s %d 米", distanceCondition, task.getDiscussDistance())); |             holder.tvTaskDistance.setText(String.format("条件:%s %d 米", distanceCondition, task.getDiscussDistance())); | ||||||
|  |  | ||||||
|             holder.cbTaskEnable.setChecked(task.isEnable()); |             holder.cbTaskEnable.setChecked(task.isEnable()); | ||||||
|             holder.cbTaskEnable.setEnabled(mCurrentViewMode == VIEW_MODE_EDIT); // 仅编辑模式可点击 |             holder.cbTaskEnable.setEnabled(mCurrentViewMode == VIEW_MODE_EDIT); | ||||||
|  |  | ||||||
|             // 2. 编辑模式处理(核心:修复开关监听重复绑定+修改同步) |  | ||||||
|             if (mCurrentViewMode == VIEW_MODE_EDIT) { |             if (mCurrentViewMode == VIEW_MODE_EDIT) { | ||||||
|                 holder.btnEditTask.setVisibility(View.VISIBLE); |                 holder.btnEditTask.setVisibility(View.VISIBLE); | ||||||
|                 holder.btnDeleteTask.setVisibility(View.VISIBLE); |                 holder.btnDeleteTask.setVisibility(View.VISIBLE); | ||||||
|  |  | ||||||
|                 // (1)删除按钮逻辑 |  | ||||||
|                 holder.btnDeleteTask.setOnClickListener(new View.OnClickListener() { |                 holder.btnDeleteTask.setOnClickListener(new View.OnClickListener() { | ||||||
| 						@Override | 						@Override | ||||||
| 						public void onClick(View v) { | 						public void onClick(View v) { | ||||||
| 							mData.remove(position); // 移除数据源中任务 | 							mData.remove(position); | ||||||
| 							notifyItemRemoved(position); // 刷新列表(移除项) | 							notifyItemRemoved(position); | ||||||
| 							notifyItemRangeChanged(position, mData.size()); // 刷新后续项索引 | 							notifyItemRangeChanged(position, mData.size()); | ||||||
| 							// 同步通知外部 |  | ||||||
| 							if (mOnTaskUpdatedListener != null && mBindPositionId != null) { | 							if (mOnTaskUpdatedListener != null && mBindPositionId != null) { | ||||||
| 								mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData)); | 								mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData)); | ||||||
| 							} | 							} | ||||||
| @@ -254,7 +247,6 @@ public class PositionTaskListView extends LinearLayout { | |||||||
| 						} | 						} | ||||||
| 					}); | 					}); | ||||||
|  |  | ||||||
|                 // (2)修改按钮逻辑(弹窗编辑) |  | ||||||
|                 holder.btnEditTask.setOnClickListener(new View.OnClickListener() { |                 holder.btnEditTask.setOnClickListener(new View.OnClickListener() { | ||||||
| 						@Override | 						@Override | ||||||
| 						public void onClick(View v) { | 						public void onClick(View v) { | ||||||
| @@ -262,45 +254,37 @@ public class PositionTaskListView extends LinearLayout { | |||||||
| 						} | 						} | ||||||
| 					}); | 					}); | ||||||
|  |  | ||||||
|                 // (核心修复1:绑定新监听前先移除旧监听,避免重复触发) |  | ||||||
|                 holder.cbTaskEnable.setOnCheckedChangeListener(null); |                 holder.cbTaskEnable.setOnCheckedChangeListener(null); | ||||||
|                 holder.cbTaskEnable.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { |                 holder.cbTaskEnable.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | ||||||
| 						@Override | 						@Override | ||||||
| 						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | 						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | ||||||
| 							task.setIsEnable(isChecked); // 直接修改数据源中任务的启用状态 | 							task.setIsEnable(isChecked); | ||||||
| 							notifyItemChanged(position); // 实时刷新当前项(显示最新状态) | 							notifyItemChanged(position); | ||||||
| 							// 同步通知外部 |  | ||||||
| 							if (mOnTaskUpdatedListener != null && mBindPositionId != null) { | 							if (mOnTaskUpdatedListener != null && mBindPositionId != null) { | ||||||
| 								mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData)); | 								mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData)); | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 					}); | 					}); | ||||||
|             } else { |             } else { | ||||||
|                 // 简单模式:隐藏编辑按钮+移除监听 |  | ||||||
|                 holder.btnEditTask.setVisibility(View.GONE); |                 holder.btnEditTask.setVisibility(View.GONE); | ||||||
|                 holder.btnDeleteTask.setVisibility(View.GONE); |                 holder.btnDeleteTask.setVisibility(View.GONE); | ||||||
|                 holder.cbTaskEnable.setOnCheckedChangeListener(null); |                 holder.cbTaskEnable.setOnCheckedChangeListener(null); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /** |         // ---------------------- 原有编辑弹窗逻辑(完全不变) ---------------------- | ||||||
|          * 任务编辑弹窗(核心修复2:修改后实时刷新+同步数据) |  | ||||||
|          */ |  | ||||||
|         private void showTaskEditDialog(final PositionTaskModel task, final int position) { |         private void showTaskEditDialog(final PositionTaskModel task, final int position) { | ||||||
|             final Context context = getContext(); |             final Context context = getContext(); | ||||||
|             // 加载弹窗布局(dialog_edit_task.xml) |  | ||||||
|             View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_edit_task, null); |             View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_edit_task, null); | ||||||
|  |  | ||||||
|             // 绑定弹窗控件 |  | ||||||
|             final EditText etEditDesc = (EditText) dialogView.findViewById(R.id.et_edit_task_desc); |             final EditText etEditDesc = (EditText) dialogView.findViewById(R.id.et_edit_task_desc); | ||||||
|             final RadioGroup rgDistanceCondition = (RadioGroup) dialogView.findViewById(R.id.rg_distance_condition); |             final RadioGroup rgDistanceCondition = (RadioGroup) dialogView.findViewById(R.id.rg_distance_condition); | ||||||
|             final EditText etEditDistance = (EditText) dialogView.findViewById(R.id.et_edit_distance); |             final EditText etEditDistance = (EditText) dialogView.findViewById(R.id.et_edit_distance); | ||||||
|             Button btnCancel = (Button) dialogView.findViewById(R.id.btn_dialog_cancel); |             Button btnCancel = (Button) dialogView.findViewById(R.id.btn_dialog_cancel); | ||||||
|             Button btnSave = (Button) dialogView.findViewById(R.id.btn_dialog_save); |             Button btnSave = (Button) dialogView.findViewById(R.id.btn_dialog_save); | ||||||
|  |  | ||||||
|             // 初始化弹窗数据(显示当前任务信息) |  | ||||||
|             etEditDesc.setText(task.getTaskDescription()); |             etEditDesc.setText(task.getTaskDescription()); | ||||||
|             etEditDesc.setSelection(etEditDesc.getText().length()); // 光标定位到末尾 |             etEditDesc.setSelection(etEditDesc.getText().length()); | ||||||
|  |  | ||||||
|             if (task.isGreaterThan()) { |             if (task.isGreaterThan()) { | ||||||
|                 rgDistanceCondition.check(R.id.rb_greater_than); |                 rgDistanceCondition.check(R.id.rb_greater_than); | ||||||
| @@ -310,13 +294,11 @@ public class PositionTaskListView extends LinearLayout { | |||||||
|  |  | ||||||
|             etEditDistance.setText(String.valueOf(task.getDiscussDistance())); |             etEditDistance.setText(String.valueOf(task.getDiscussDistance())); | ||||||
|  |  | ||||||
|             // 创建并显示弹窗 |  | ||||||
|             final android.app.AlertDialog dialog = new android.app.AlertDialog.Builder(context) |             final android.app.AlertDialog dialog = new android.app.AlertDialog.Builder(context) | ||||||
| 				.setView(dialogView) | 				.setView(dialogView) | ||||||
| 				.create(); | 				.create(); | ||||||
|             dialog.show(); |             dialog.show(); | ||||||
|  |  | ||||||
|             // 取消按钮:关闭弹窗(不保存) |  | ||||||
|             btnCancel.setOnClickListener(new View.OnClickListener() { |             btnCancel.setOnClickListener(new View.OnClickListener() { | ||||||
| 					@Override | 					@Override | ||||||
| 					public void onClick(View v) { | 					public void onClick(View v) { | ||||||
| @@ -324,11 +306,9 @@ public class PositionTaskListView extends LinearLayout { | |||||||
| 					} | 					} | ||||||
| 				}); | 				}); | ||||||
|  |  | ||||||
|             // 保存按钮:校验+更新+同步(核心修复:实时刷新列表) |  | ||||||
|             btnSave.setOnClickListener(new View.OnClickListener() { |             btnSave.setOnClickListener(new View.OnClickListener() { | ||||||
| 					@Override | 					@Override | ||||||
| 					public void onClick(View v) { | 					public void onClick(View v) { | ||||||
| 						// 1. 输入校验 |  | ||||||
| 						String newDesc = etEditDesc.getText().toString().trim(); | 						String newDesc = etEditDesc.getText().toString().trim(); | ||||||
| 						String distanceStr = etEditDistance.getText().toString().trim(); | 						String distanceStr = etEditDistance.getText().toString().trim(); | ||||||
|  |  | ||||||
| @@ -340,7 +320,7 @@ public class PositionTaskListView extends LinearLayout { | |||||||
| 						int newDistance; | 						int newDistance; | ||||||
| 						try { | 						try { | ||||||
| 							newDistance = Integer.parseInt(distanceStr); | 							newDistance = Integer.parseInt(distanceStr); | ||||||
| 							if (newDistance < 1) { // 距离最小为1米,避免无效值 | 							if (newDistance < 1) { | ||||||
| 								Toast.makeText(context, "距离不能小于1米", Toast.LENGTH_SHORT).show(); | 								Toast.makeText(context, "距离不能小于1米", Toast.LENGTH_SHORT).show(); | ||||||
| 								return; | 								return; | ||||||
| 							} | 							} | ||||||
| @@ -349,69 +329,66 @@ public class PositionTaskListView extends LinearLayout { | |||||||
| 							return; | 							return; | ||||||
| 						} | 						} | ||||||
|  |  | ||||||
| 						// 2. 更新任务数据(直接修改数据源中的任务对象,强引用同步) |  | ||||||
| 						task.setTaskDescription(newDesc); | 						task.setTaskDescription(newDesc); | ||||||
| 						task.setDiscussDistance(newDistance); | 						task.setDiscussDistance(newDistance); | ||||||
| 						// 更新距离条件(大于/小于) |  | ||||||
| 						boolean isGreater = rgDistanceCondition.getCheckedRadioButtonId() == R.id.rb_greater_than; | 						boolean isGreater = rgDistanceCondition.getCheckedRadioButtonId() == R.id.rb_greater_than; | ||||||
| 						task.setIsGreaterThan(isGreater); | 						task.setIsGreaterThan(isGreater); | ||||||
| 						// 强制绑定当前位置ID,避免任务串位 |  | ||||||
| 						task.setPositionId(mBindPositionId); | 						task.setPositionId(mBindPositionId); | ||||||
|  |  | ||||||
| 						// 3. 核心修复:实时刷新当前任务项,确保修改后立即显示 |  | ||||||
| 						notifyItemChanged(position); | 						notifyItemChanged(position); | ||||||
|  |  | ||||||
| 						// 4. 同步通知外部Adapter更新全局数据 |  | ||||||
| 						if (mOnTaskUpdatedListener != null && mBindPositionId != null) { | 						if (mOnTaskUpdatedListener != null && mBindPositionId != null) { | ||||||
| 							mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData)); | 							mOnTaskUpdatedListener.onTaskUpdated(mBindPositionId, new ArrayList<PositionTaskModel>(mData)); | ||||||
| 						} | 						} | ||||||
|  |  | ||||||
| 						// 5. 关闭弹窗并提示 |  | ||||||
| 						dialog.dismiss(); | 						dialog.dismiss(); | ||||||
| 						Toast.makeText(context, "任务已更新", Toast.LENGTH_SHORT).show(); | 						Toast.makeText(context, "任务已更新", Toast.LENGTH_SHORT).show(); | ||||||
| 					} | 					} | ||||||
| 				}); | 				}); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // ---------------------- ViewHolder 定义(内部类,绑定布局控件) ---------------------- |         // ---------------------- ViewHolder 定义(新增简单模式 Holder,适配红点) ---------------------- | ||||||
|         /** |         // 基础抽象 ViewHolder(不变) | ||||||
|          * 基础ViewHolder(抽象类,统一父类型) |  | ||||||
|          */ |  | ||||||
|         public abstract class TaskViewHolder extends RecyclerView.ViewHolder { |         public abstract class TaskViewHolder extends RecyclerView.ViewHolder { | ||||||
|             public TaskViewHolder(@NonNull View itemView) { |             public TaskViewHolder(@NonNull View itemView) { | ||||||
|                 super(itemView); |                 super(itemView); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /** |         // 空提示 Holder(不变) | ||||||
|          * 空提示ViewHolder(绑定“无任务”提示布局 item_task_empty.xml) |  | ||||||
|          */ |  | ||||||
|         public class EmptyViewHolder extends TaskViewHolder { |         public class EmptyViewHolder extends TaskViewHolder { | ||||||
|             public EmptyViewHolder(@NonNull View itemView) { |             public EmptyViewHolder(@NonNull View itemView) { | ||||||
|                 super(itemView); |                 super(itemView); | ||||||
|                 // 根据当前视图模式修改提示文本 |  | ||||||
|                 TextView tvEmptyTip = (TextView) itemView.findViewById(R.id.tv_task_empty_tip); |  | ||||||
|                 if (mCurrentViewMode == VIEW_MODE_EDIT) { |  | ||||||
|                     tvEmptyTip.setText("暂无任务,点击\"添加新任务\"创建"); |  | ||||||
|                 } else { |  | ||||||
|                     tvEmptyTip.setText("暂无启用的任务"); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /** |         // 新增:简单模式 Holder(绑定带红点的布局控件) | ||||||
|          * 任务内容ViewHolder(绑定任务项布局 item_task_content.xml) |         public class SimpleTaskViewHolder extends TaskViewHolder { | ||||||
|          */ |             TextView tvSimpleTaskDesc;    // 任务描述 | ||||||
|  |             TextView tvSimpleDistanceCond;// 距离条件 | ||||||
|  |             TextView tvSimpleIsEnable;    // 启用状态 | ||||||
|  |             View vBingoDot;               // isBingo 红点控件 | ||||||
|  |  | ||||||
|  |             public SimpleTaskViewHolder(@NonNull View itemView) { | ||||||
|  |                 super(itemView); | ||||||
|  |                 // 绑定简单模式布局中的控件(与 item_task_simple.xml 完全对应) | ||||||
|  |                 tvSimpleTaskDesc = itemView.findViewById(R.id.tv_simple_task_desc); | ||||||
|  |                 tvSimpleDistanceCond = itemView.findViewById(R.id.tv_simple_distance_cond); | ||||||
|  |                 tvSimpleIsEnable = itemView.findViewById(R.id.tv_simple_is_enable); | ||||||
|  |                 vBingoDot = itemView.findViewById(R.id.v_bingo_dot); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 编辑模式 Holder(原有逻辑,完全不变) | ||||||
|         public class TaskContentViewHolder extends TaskViewHolder { |         public class TaskContentViewHolder extends TaskViewHolder { | ||||||
|             TextView tvTaskDesc;       // 任务描述 |             TextView tvTaskDesc; | ||||||
|             TextView tvTaskDistance;   // 距离条件(如“大于 100 米”) |             TextView tvTaskDistance; | ||||||
|             CompoundButton cbTaskEnable; // 任务启用/禁用开关 |             CompoundButton cbTaskEnable; | ||||||
|             Button btnEditTask;        // 编辑任务按钮 |             Button btnEditTask; | ||||||
|             Button btnDeleteTask;      // 删除任务按钮 |             Button btnDeleteTask; | ||||||
|  |  | ||||||
|             public TaskContentViewHolder(@NonNull View itemView) { |             public TaskContentViewHolder(@NonNull View itemView) { | ||||||
|                 super(itemView); |                 super(itemView); | ||||||
|                 // 绑定布局控件(与 item_task_content.xml 中的ID严格对应) |  | ||||||
|                 tvTaskDesc = (TextView) itemView.findViewById(R.id.tv_task_desc); |                 tvTaskDesc = (TextView) itemView.findViewById(R.id.tv_task_desc); | ||||||
|                 tvTaskDistance = (TextView) itemView.findViewById(R.id.tv_task_distance); |                 tvTaskDistance = (TextView) itemView.findViewById(R.id.tv_task_distance); | ||||||
|                 cbTaskEnable = (CompoundButton) itemView.findViewById(R.id.cb_task_enable); |                 cbTaskEnable = (CompoundButton) itemView.findViewById(R.id.cb_task_enable); | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								positions/src/main/res/drawable/bg_bingo_dot.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								positions/src/main/res/drawable/bg_bingo_dot.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <shape xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     android:shape="oval">  <!-- 形状:圆形 --> | ||||||
|  |     <solid android:color="#FF4444"/>  <!-- 填充色:亮红色(可调整色值) --> | ||||||
|  |     <stroke | ||||||
|  |         android:width="1dp" | ||||||
|  |         android:color="#FFFFFF"/> | ||||||
|  | </shape> | ||||||
| @@ -1,60 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> |  | ||||||
| <!-- 列表项布局:左侧显示经纬度/备注,右侧添加删除按钮 --> |  | ||||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |  | ||||||
|     android:layout_width="match_parent" |  | ||||||
|     android:layout_height="wrap_content" |  | ||||||
|     android:orientation="horizontal" |  | ||||||
|     android:padding="12dp" |  | ||||||
|     android:background="@drawable/item_position_bg" |  | ||||||
|     android:layout_marginBottom="8dp" |  | ||||||
|     android:gravity="center_vertical"> <!-- 内容与按钮垂直居中对齐 --> |  | ||||||
|  |  | ||||||
|     <!-- 左侧:内容区(经纬度+备注,垂直排列,占满剩余宽度) --> |  | ||||||
|     <LinearLayout |  | ||||||
|         android:layout_width="0dp" |  | ||||||
|         android:layout_height="wrap_content" |  | ||||||
|         android:layout_weight="1" |  | ||||||
|         android:orientation="vertical" |  | ||||||
|         android:clickable="false"> <!-- 内容区禁止点击响应 --> |  | ||||||
|  |  | ||||||
|         <TextView |  | ||||||
|             android:id="@+id/tv_item_longitude" |  | ||||||
|             android:layout_width="wrap_content" |  | ||||||
|             android:layout_height="wrap_content" |  | ||||||
|             android:textSize="14sp" |  | ||||||
|             android:textColor="#666666"/> |  | ||||||
|  |  | ||||||
|         <TextView |  | ||||||
|             android:id="@+id/tv_item_latitude" |  | ||||||
|             android:layout_width="wrap_content" |  | ||||||
|             android:layout_height="wrap_content" |  | ||||||
|             android:textSize="14sp" |  | ||||||
|             android:textColor="#666666" |  | ||||||
|             android:layout_marginTop="5dp"/> |  | ||||||
|  |  | ||||||
|         <TextView |  | ||||||
|             android:id="@+id/tv_item_memo" |  | ||||||
|             android:layout_width="wrap_content" |  | ||||||
|             android:layout_height="wrap_content" |  | ||||||
|             android:textSize="16sp" |  | ||||||
|             android:textColor="#000000" |  | ||||||
|             android:textStyle="bold" |  | ||||||
|             android:layout_marginTop="8dp"/> |  | ||||||
|  |  | ||||||
|     </LinearLayout> |  | ||||||
|  |  | ||||||
|     <!-- 右侧:删除按钮(红色图标/文字,仅按钮可点击) --> |  | ||||||
|     <Button |  | ||||||
|         android:id="@+id/btn_item_delete" |  | ||||||
|         android:layout_width="wrap_content" |  | ||||||
|         android:layout_height="30dp" |  | ||||||
|         android:layout_marginStart="10dp" |  | ||||||
|         android:background="@drawable/btn_delete_bg" |  | ||||||
|         android:text="删除" |  | ||||||
|         android:textColor="@android:color/white" |  | ||||||
|         android:textSize="12sp" |  | ||||||
|         android:paddingStart="12dp" |  | ||||||
|         android:paddingEnd="12dp"/> |  | ||||||
|  |  | ||||||
| </LinearLayout> |  | ||||||
|  |  | ||||||
| @@ -161,7 +161,7 @@ | |||||||
| 		<cc.winboll.studio.positions.views.PositionTaskListView | 		<cc.winboll.studio.positions.views.PositionTaskListView | ||||||
| 			android:id="@+id/ptlv_edit_tasks" | 			android:id="@+id/ptlv_edit_tasks" | ||||||
| 			android:layout_width="match_parent" | 			android:layout_width="match_parent" | ||||||
| 			android:layout_height="400dp" | 			android:layout_height="wrap_content" | ||||||
| 			android:layout_marginTop="6dp"/> | 			android:layout_marginTop="6dp"/> | ||||||
|  |  | ||||||
| 	</LinearLayout> | 	</LinearLayout> | ||||||
|   | |||||||
| @@ -48,7 +48,7 @@ | |||||||
|     <cc.winboll.studio.positions.views.PositionTaskListView |     <cc.winboll.studio.positions.views.PositionTaskListView | ||||||
|         android:id="@+id/ptlv_simple_tasks" |         android:id="@+id/ptlv_simple_tasks" | ||||||
|         android:layout_width="match_parent" |         android:layout_width="match_parent" | ||||||
|         android:layout_height="200dp" |         android:layout_height="wrap_content" | ||||||
|         android:layout_marginTop="4dp"/> |         android:layout_marginTop="4dp"/> | ||||||
|  |  | ||||||
| </LinearLayout> | </LinearLayout> | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | <!-- 根布局改为 RelativeLayout,支持红点右上角定位(原 LinearLayout 无法便捷实现绝对位置) --> | ||||||
|  | <RelativeLayout  | ||||||
|  |     xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|     android:layout_width="match_parent" |     android:layout_width="match_parent" | ||||||
|     android:layout_height="wrap_content" |     android:layout_height="wrap_content" | ||||||
|     android:orientation="vertical" |     android:orientation="vertical" | ||||||
| @@ -7,7 +9,19 @@ | |||||||
|     android:background="@drawable/item_bg_simple" |     android:background="@drawable/item_bg_simple" | ||||||
|     android:layout_marginBottom="8dp"> |     android:layout_marginBottom="8dp"> | ||||||
|  |  | ||||||
|     <!-- 任务描述 --> |     <!-- 1. 右上角小红点(仅 isBingo=true 时显示,绑定 isBingo 属性) --> | ||||||
|  |     <View | ||||||
|  |         android:id="@+id/v_bingo_dot" | ||||||
|  |         android:layout_width="12dp" | ||||||
|  |         android:layout_height="12dp" | ||||||
|  |         android:layout_alignParentRight="true" | ||||||
|  |         android:layout_alignParentTop="true" | ||||||
|  |         android:layout_marginRight="2dp" | ||||||
|  |         android:layout_marginTop="2dp" | ||||||
|  |         android:background="@drawable/bg_bingo_dot" | ||||||
|  |         android:visibility="gone"/>  <!-- 默认隐藏,仅任务触发(isBingo=true)时显示 --> | ||||||
|  |  | ||||||
|  |     <!-- 2. 任务描述(原控件不变,位置受红点不影响) --> | ||||||
|     <TextView |     <TextView | ||||||
|         android:id="@+id/tv_simple_task_desc" |         android:id="@+id/tv_simple_task_desc" | ||||||
|         android:layout_width="wrap_content" |         android:layout_width="wrap_content" | ||||||
| @@ -16,7 +30,7 @@ | |||||||
|         android:textColor="#333333" |         android:textColor="#333333" | ||||||
|         android:text="任务:无描述"/> |         android:text="任务:无描述"/> | ||||||
|  |  | ||||||
|     <!-- 距离条件 --> |     <!-- 3. 距离条件(原控件不变) --> | ||||||
|     <TextView |     <TextView | ||||||
|         android:id="@+id/tv_simple_distance_cond" |         android:id="@+id/tv_simple_distance_cond" | ||||||
|         android:layout_width="wrap_content" |         android:layout_width="wrap_content" | ||||||
| @@ -24,9 +38,10 @@ | |||||||
|         android:textSize="14sp" |         android:textSize="14sp" | ||||||
|         android:textColor="#666666" |         android:textColor="#666666" | ||||||
|         android:layout_marginTop="6dp" |         android:layout_marginTop="6dp" | ||||||
|  |         android:layout_below="@id/tv_simple_task_desc" | ||||||
|         android:text="条件:距离 > 0 米"/> |         android:text="条件:距离 > 0 米"/> | ||||||
|  |  | ||||||
|     <!-- 启用状态(简单视图仅显示“已启用”) --> |     <!-- 4. 启用状态(原控件不变) --> | ||||||
|     <TextView |     <TextView | ||||||
|         android:id="@+id/tv_simple_is_enable" |         android:id="@+id/tv_simple_is_enable" | ||||||
|         android:layout_width="wrap_content" |         android:layout_width="wrap_content" | ||||||
| @@ -34,7 +49,8 @@ | |||||||
|         android:textSize="14sp" |         android:textSize="14sp" | ||||||
|         android:textColor="#2E8B57" |         android:textColor="#2E8B57" | ||||||
|         android:layout_marginTop="4dp" |         android:layout_marginTop="4dp" | ||||||
|  |         android:layout_below="@id/tv_simple_distance_cond" | ||||||
|         android:text="状态:已启用"/> |         android:text="状态:已启用"/> | ||||||
|  |  | ||||||
| </LinearLayout> | </RelativeLayout> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen