@@ -1,19 +1,12 @@
package cc.winboll.studio.positions.adapters ;
package cc.winboll.studio.positions.adapters ;
/**
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/09/29 20:25
* @Describe 位置数据适配器( 修复视图复用资源加载, 支持滚动后重新绑定数据, Java 7语法适配)
* @Describe 位置数据适配器( 修复视图复用资源加载, 支持滚动后重新绑定数据, Java 7语法适配)
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @CreateTime 2025-09-29 20:25:00
* @EditTime 2026-03-31 23:14:55
*/
*/
/**
* Java 7 语法严格适配 + 视图复用资源加载修复:
* 1. 保留无Lambda/弱引用/线程安全集合等原有适配
* 2. 修复核心问题:移除 onViewDetachedFromWindow 中关键资源释放,改为 onBind 时重新绑定
* 3. 强化资源复用:任务视图/距离控件在复用后自动从服务同步最新数据,确保滚动后数据不丢失
* 4. 优化缓存逻辑:仅清理脱离屏幕且无效的控件缓存,有效控件保留引用供局部更新(如距离)
*/
import android.content.Context ;
import android.content.Context ;
import android.text.TextUtils ;
import android.text.TextUtils ;
import android.view.LayoutInflater ;
import android.view.LayoutInflater ;
@@ -36,32 +29,32 @@ import java.util.ArrayList;
import java.util.Iterator ;
import java.util.Iterator ;
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.ConcurrentHashMap ;
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 " ;
// 视图类型常量(静态常量统一管理)
// 视图类型常量
private static final int VIEW_TYPE_SIMPLE = 0 ;
private static final int VIEW_TYPE_SIMPLE = 0 ;
private static final int VIEW_TYPE_EDIT = 1 ;
private static final int VIEW_TYPE_EDIT = 1 ;
// 默认配置常量(避免魔法值)
// 默认配置常量
private static final String DEFAULT_MEMO = " 无备注 " ;
private static final String DEFAULT_MEMO = " 无备注 " ;
private static final String DEFAULT_TASK_DESC = " 新任务 " ;
private static final String DEFAULT_TASK_DESC = " 新任务 " ;
private static final int DEFAULT_TASK_DISTANCE = 50 ; // 单位:米
private static final int DEFAULT_TASK_DISTANCE = 50 ;
private static final String DISTANCE_FORMAT = " 实时距离:%.1f 米 " ;
private static final String DISTANCE_FORMAT = " 实时距离:%.1f 米 " ;
private static final String DISTANCE_DISABLED = " 实时距离:未启用 " ;
private static final String DISTANCE_DISABLED = " 实时距离:未启用 " ;
private static final String DISTANCE_ERROR = " 实时距离:计算失败 " ;
private static final String DISTANCE_ERROR = " 实时距离:计算失败 " ;
// 核心依赖(弱引用+线程安全集合, 适配Java 7)
// 核心成员变量
private final Context mContext ;
private final Context mContext ;
private final ArrayList < PositionModel > mCachedPositionList ; // 位置缓存( 与MainService同步)
private final ArrayList < PositionModel > mCachedPositionList ;
private final WeakReference < MainService > mMainServiceRef ; // 弱引用MainService, 防内存泄漏
private final WeakReference < MainService > mMainServiceRef ;
// 控件缓存: 位置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, 保留有效引用避免复用后更新失效)
private final ConcurrentHashMap < String , TextView > mPosDistanceViewMap ;
private final ConcurrentHashMap < String , TextView > mPosDistanceViewMap ;
// 回调接口( 仅处理位置逻辑, 任务逻辑通过PositionTaskListView+MainService完成)
// 回调接口
public interface OnDeleteClickListener {
public interface OnDeleteClickListener {
void onDeleteClick ( int position ) ;
void onDeleteClick ( int position ) ;
}
}
@@ -74,32 +67,32 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private OnSavePositionClickListener mOnSavePosListener ;
private OnSavePositionClickListener mOnSavePosListener ;
// =========================================================================
// =========================================================================
// 构造函数(初始化依赖+注册服务监听+初始化控件缓存)
// 构造函数
// =========================================================================
// =========================================================================
public PositionAdapter ( Context context , ArrayList < PositionModel > cachedPositionList , MainService mainService ) {
public PositionAdapter ( Context context , ArrayList < PositionModel > cachedPositionList , MainService mainService ) {
LogUtils . d ( TAG , " PositionAdapter 构造函数开始, context= " + context
+ " , cachedPositionList=" + ( cachedPositionList ! = null ? cachedPositionList . size ( ) : 0 )
+ " , mainService=" + mainService ) ;
this . mContext = context ;
this . mContext = context ;
// 容错处理: 避免传入null导致空指针
this . mCachedPositionList = ( cachedPositionList ! = null ) ? cachedPositionList : new ArrayList < PositionModel > ( ) ;
this . mCachedPositionList = ( cachedPositionList ! = null ) ? cachedPositionList : new ArrayList < PositionModel > ( ) ;
// 弱引用MainService: 防止Adapter持有服务导致内存泄漏( Java 7 弱引用语法)
this . mMainServiceRef = new WeakReference < MainService > ( mainService ) ;
this . mMainServiceRef = new WeakReference < MainService > ( mainService ) ;
// 初始化控件缓存(线程安全集合,适配多线程更新场景)
this . mSimpleTaskViewMap = new ConcurrentHashMap < String , PositionTaskListView > ( ) ;
this . mSimpleTaskViewMap = new ConcurrentHashMap < String , PositionTaskListView > ( ) ;
this . mEditTaskViewMap = new ConcurrentHashMap < String , PositionTaskListView > ( ) ;
this . mEditTaskViewMap = new ConcurrentHashMap < String , PositionTaskListView > ( ) ;
this . mPosDistanceViewMap = new ConcurrentHashMap < String , TextView > ( ) ;
this . mPosDistanceViewMap = new ConcurrentHashMap < String , TextView > ( ) ;
// 注册MainService任务监听: 服务任务变化时同步刷新任务列表视图
if ( mainService ! = null ) {
if ( mainService ! = null ) {
mainService . registerTaskUpdateListener ( this ) ;
mainService . registerTaskUpdateListener ( this ) ;
LogUtils . d ( TAG , " 已注册MainService任务监听,确保任务数据与服务同步 " ) ;
LogUtils . d ( TAG , " 已注册 MainService 任务监听 " ) ;
} else {
} else {
LogUtils . w ( TAG , " 构造函数: MainService为空, PositionTaskListView 无法初始化 " ) ;
LogUtils . w ( TAG , " 构造函数: MainService 为空,无法初始化任务视图 " ) ;
}
}
LogUtils . d ( TAG , " Adapter初始化完成: 位置数量= " + mCachedPositionList . size ( ) ) ;
LogUtils . d ( TAG , " Position Adapter 初始化完成, 位置数量=" + mCachedPositionList . size ( ) ) ;
}
}
// =========================================================================
// =========================================================================
// RecyclerView 核心方法(强化视图复用逻辑,复用后自动重新绑定资源)
// RecyclerView 核心方法
// =========================================================================
// =========================================================================
@Override
@Override
public int getItemViewType ( int position ) {
public int getItemViewType ( int position ) {
@@ -109,6 +102,7 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
@Override
@Override
public RecyclerView . ViewHolder onCreateViewHolder ( ViewGroup parent , int viewType ) {
public RecyclerView . ViewHolder onCreateViewHolder ( ViewGroup parent , int viewType ) {
LogUtils . d ( TAG , " onCreateViewHolder viewType= " + viewType ) ;
LayoutInflater inflater = LayoutInflater . from ( mContext ) ;
LayoutInflater inflater = LayoutInflater . from ( mContext ) ;
if ( viewType = = VIEW_TYPE_SIMPLE ) {
if ( viewType = = VIEW_TYPE_SIMPLE ) {
View simpleView = inflater . inflate ( R . layout . item_position_simple , parent , false ) ;
View simpleView = inflater . inflate ( R . layout . item_position_simple , parent , false ) ;
@@ -121,34 +115,28 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
@Override
@Override
public void onBindViewHolder ( RecyclerView . ViewHolder holder , int position ) {
public void onBindViewHolder ( RecyclerView . ViewHolder holder , int position ) {
LogUtils . d ( TAG , " onBindViewHolder position= " + position ) ;
PositionModel posModel = getPositionByIndex ( position ) ;
PositionModel posModel = getPositionByIndex ( position ) ;
if ( posModel = = null ) {
if ( posModel = = null ) {
LogUtils . w ( TAG , " onBindViewHolder: 位置模型为空( 索引= " + position + " ),跳过绑定 " ) ;
LogUtils . w ( TAG , " onBindViewHolder: 位置模型为空, 索引= " + position ) ;
return ;
return ;
}
}
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 ) ;
LogUtils . d ( TAG , " 绑定 SimpleViewHolder, posId =" + posId ) ;
SimpleViewHolder simpleHolder = ( SimpleViewHolder ) holder ;
SimpleViewHolder simpleHolder = ( SimpleViewHolder ) holder ;
// 1. 重新绑定位置基础数据(经纬度/备注/距离,确保复用后显示最新数据)
bindSimplePositionData ( simpleHolder , posModel ) ;
bindSimplePositionData ( simpleHolder , posModel ) ;
// 2. 重新初始化+绑定简单模式任务视图(复用后从服务同步最新任务,避免数据丢失)
initAndBindSimpleTaskView ( simpleHolder . ptlvSimpleTasks , posId , mainService ) ;
initAndBindSimpleTaskView ( simpleHolder . ptlvSimpleTasks , posId , mainService ) ;
// 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 ) ;
LogUtils . d ( TAG , " 绑定 EditViewHolder, posId =" + posId ) ;
EditViewHolder editHolder = ( EditViewHolder ) holder ;
EditViewHolder editHolder = ( EditViewHolder ) holder ;
// 1. 重新绑定位置基础数据(经纬度/备注/距离/距离开关,复用后显示最新状态)
bindEditPositionData ( editHolder , posModel , position ) ;
bindEditPositionData ( editHolder , posModel , position ) ;
// 2. 重新初始化+绑定编辑模式任务视图(复用后同步服务最新任务,支持增删改)
initAndBindEditTaskView ( editHolder . ptlvEditTasks , posId , mainService , editHolder . btnAddTask ) ;
initAndBindEditTaskView ( editHolder . ptlvEditTasks , posId , mainService , editHolder . btnAddTask ) ;
// 3. 缓存/更新编辑模式任务视图+距离控件(覆盖旧缓存,确保引用最新控件)
mEditTaskViewMap . put ( posId , editHolder . ptlvEditTasks ) ;
mEditTaskViewMap . put ( posId , editHolder . ptlvEditTasks ) ;
mPosDistanceViewMap . put ( posId , editHolder . tvEditDistance ) ;
mPosDistanceViewMap . put ( posId , editHolder . tvEditDistance ) ;
}
}
@@ -157,37 +145,33 @@ 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 ) ;
// 核心修改:仅清理「无效/已回收」的控件缓存,不释放关键资源(支持复用后重新绑定)
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. 清理「已脱离视图树/无效」的距离控件缓存(保留有效控件供局部更新)
if ( mPosDistanceViewMap . containsKey ( posId ) ) {
if ( mPosDistanceViewMap . containsKey ( posId ) ) {
TextView distanceView = mPosDistanceViewMap . get ( posId ) ;
TextView distanceView = mPosDistanceViewMap . get ( posId ) ;
if ( distanceView = = null | | ! distanceView . isAttachedToWindow ( ) ) {
if ( distanceView = = null | | ! distanceView . isAttachedToWindow ( ) ) {
mPosDistanceViewMap . remove ( posId ) ;
mPosDistanceViewMap . remove ( posId ) ;
LogUtils . d ( TAG , " 视图脱离屏幕 :移除无效距离控件缓存( 位置ID = " + posId + " ) " ) ;
LogUtils . d ( TAG , " 视图脱离:移除无效距离控件缓存 posId = " + posId ) ;
}
}
}
}
// 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 | | ! taskView . isAttachedToWindow ( ) ) {
if ( taskView = = null | | ! taskView . isAttachedToWindow ( ) ) {
mSimpleTaskViewMap . remove ( posId ) ;
mSimpleTaskViewMap . remove ( posId ) ;
LogUtils . d ( TAG , " 简单模式 视图脱离屏幕 :移除无效任务视图缓存( 位置ID =" + posId + " ) " ) ;
LogUtils . d ( TAG , " 视图脱离:移除无效简单 任务视图缓存 posId = " + posId ) ;
}
}
}
}
// 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 | | ! taskView . isAttachedToWindow ( ) ) {
if ( taskView = = null | | ! taskView . isAttachedToWindow ( ) ) {
mEditTaskViewMap . remove ( posId ) ;
mEditTaskViewMap . remove ( posId ) ;
LogUtils . d ( TAG , " 编辑模式 视图脱离屏幕 :移除无效任务视图缓存( 位置ID =" + posId + " ) " ) ;
LogUtils . d ( TAG , " 视图脱离:移除无效编辑 任务视图缓存 posId = " + posId ) ;
}
}
}
}
}
}
@@ -198,46 +182,34 @@ 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位小数, 格式统一)
LogUtils . d ( TAG , " bindSimplePositionData posId= " + posModel . getPositionId ( ) ) ;
holder . tvSimpleLon . setText ( String . format ( " 经度:%.6f " , posModel . getLongitude ( ) ) ) ;
holder . tvSimpleLon . setText ( String . format ( " 经度:%.6f " , posModel . getLongitude ( ) ) ) ;
holder . tvSimpleLat . setText ( String . format ( " 纬度:%.6f " , posModel . getLatitude ( ) ) ) ;
holder . tvSimpleLat . setText ( String . format ( " 纬度:%.6f " , posModel . getLatitude ( ) ) ) ;
// 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. 实时距离显示(按状态区分文本+颜色——复用后重新计算显示最新距离)
updateDistanceDisplay ( holder . tvSimpleDistance , posModel ) ;
updateDistanceDisplay ( holder . tvSimpleDistance , posModel ) ;
// 4. 点击切换到编辑模式
holder . itemView . setOnClickListener ( new View . OnClickListener ( ) {
holder . itemView . setOnClickListener ( new View . OnClickListener ( ) {
@Override
@Override
public void onClick ( View v ) {
public void onClick ( View v ) {
posModel . setIsSimpleView ( false ) ;
posModel . setIsSimpleView ( false ) ;
// 精准刷新当前项(避免全量刷新)
notifyItemChanged ( getPositionIndexById ( posModel . getPositionId ( ) ) ) ;
notifyItemChanged ( getPositionIndexById ( posModel . getPositionId ( ) ) ) ;
LogUtils . d ( TAG , " 简单视图点击:位置ID = " + posModel . getPositionId ( ) + " ,切换到编辑视图 " ) ;
LogUtils . d ( TAG , " 简单视图点击:切换编辑模式 posId = " + posModel . getPositionId ( ) ) ;
}
}
} ) ;
} ) ;
}
}
/**
* 绑定编辑模式位置数据(支持备注修改/距离开关/删除/保存)—— 复用后重新执行,恢复编辑状态
*/
private void bindEditPositionData ( final EditViewHolder holder , final PositionModel posModel , final int position ) {
private void bindEditPositionData ( final EditViewHolder holder , final PositionModel posModel , final int position ) {
LogUtils . d ( TAG , " bindEditPositionData posId= " + posModel . getPositionId ( ) + " position= " + position ) ;
final String posId = posModel . getPositionId ( ) ;
final String posId = posModel . getPositionId ( ) ;
// 1. 经纬度显示(不可编辑,仅展示)
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. 备注编辑(填充现有备注,光标定位到末尾——复用后恢复输入状态)
String memo = posModel . getMemo ( ) ;
String memo = posModel . getMemo ( ) ;
if ( ! TextUtils . isEmpty ( memo ) ) {
if ( ! TextUtils . isEmpty ( memo ) ) {
holder . etEditMemo . setText ( memo ) ;
holder . etEditMemo . setText ( memo ) ;
@@ -246,26 +218,22 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
holder . etEditMemo . setText ( " " ) ;
holder . etEditMemo . setText ( " " ) ;
}
}
// 3. 实时距离显示(与简单模式逻辑一致——复用后显示最新距离)
updateDistanceDisplay ( holder . tvEditDistance , posModel ) ;
updateDistanceDisplay ( holder . tvEditDistance , posModel ) ;
// 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 ) ;
// 5. 取消编辑:切换回简单模式+隐藏软键盘
holder . btnCancel . setOnClickListener ( new View . OnClickListener ( ) {
holder . btnCancel . setOnClickListener ( new View . OnClickListener ( ) {
@Override
@Override
public void onClick ( View v ) {
public void onClick ( View v ) {
posModel . setIsSimpleView ( true ) ;
posModel . setIsSimpleView ( true ) ;
notifyItemChanged ( position ) ;
notifyItemChanged ( position ) ;
hideSoftKeyboard ( v ) ;
hideSoftKeyboard ( v ) ;
LogUtils . d ( TAG , " 取消编辑:位置ID = " + posId + " ,切换回简单视图 " ) ;
LogUtils . d ( TAG , " 取消编辑:切换简单视图 posId = " + posId ) ;
}
}
} ) ;
} ) ;
// 6. 删除位置: 回调Activity处理( Adapter不直接操作数据)
holder . btnDelete . setOnClickListener ( new View . OnClickListener ( ) {
holder . btnDelete . setOnClickListener ( new View . OnClickListener ( ) {
@Override
@Override
public void onClick ( View v ) {
public void onClick ( View v ) {
@@ -273,19 +241,16 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
mOnDeleteListener . onDeleteClick ( position ) ;
mOnDeleteListener . onDeleteClick ( position ) ;
}
}
hideSoftKeyboard ( v ) ;
hideSoftKeyboard ( v ) ;
LogUtils . d ( TAG , " 触发删除: 通知Activity处理位置ID = " + posId + " 的删除逻辑 " ) ;
LogUtils . d ( TAG , " 触发删除位置 posId = " + posId ) ;
}
}
} ) ;
} ) ;
// 7. 保存位置: 收集参数→更新模型→回调Activity→切换视图
holder . btnSave . setOnClickListener ( new View . OnClickListener ( ) {
holder . btnSave . setOnClickListener ( new View . OnClickListener ( ) {
@Override
@Override
public void onClick ( View v ) {
public void onClick ( View v ) {
// 收集编辑后的数据
String newMemo = holder . etEditMemo . getText ( ) . toString ( ) . trim ( ) ;
String newMemo = holder . etEditMemo . getText ( ) . toString ( ) . trim ( ) ;
boolean isDistanceEnable = ( holder . rgDistanceSwitch . getCheckedRadioButtonId ( ) = = R . id . rb_distance_enable ) ;
boolean isDistanceEnable = ( holder . rgDistanceSwitch . getCheckedRadioButtonId ( ) = = R . id . rb_distance_enable ) ;
// 构建更新后的位置模型(保留核心不可编辑字段)
PositionModel updatedPos = new PositionModel ( ) ;
PositionModel updatedPos = new PositionModel ( ) ;
updatedPos . setPositionId ( posId ) ;
updatedPos . setPositionId ( posId ) ;
updatedPos . setLongitude ( posModel . getLongitude ( ) ) ;
updatedPos . setLongitude ( posModel . getLongitude ( ) ) ;
@@ -294,176 +259,144 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
updatedPos . setIsEnableRealPositionDistance ( isDistanceEnable ) ;
updatedPos . setIsEnableRealPositionDistance ( isDistanceEnable ) ;
updatedPos . setIsSimpleView ( true ) ;
updatedPos . setIsSimpleView ( true ) ;
// 回调Activity保存( 由Activity同步MainService)
if ( mOnSavePosListener ! = null ) {
if ( mOnSavePosListener ! = null ) {
mOnSavePosListener . onSavePositionClick ( position , updatedPos ) ;
mOnSavePosListener . onSavePositionClick ( position , updatedPos ) ;
}
}
// 本地同步状态(避免刷新延迟)
posModel . setMemo ( newMemo ) ;
posModel . setMemo ( newMemo ) ;
posModel . setIsEnableRealPositionDistance ( isDistanceEnable ) ;
posModel . setIsEnableRealPositionDistance ( isDistanceEnable ) ;
posModel . setIsSimpleView ( true ) ;
posModel . setIsSimpleView ( true ) ;
notifyItemChanged ( position ) ;
notifyItemChanged ( position ) ;
hideSoftKeyboard ( v ) ;
hideSoftKeyboard ( v ) ;
LogUtils . d ( TAG , " 保存位置: ID= " + posId + " ,新备注= " + newMemo + " ,距离启用= " + isDistanceEnable ) ;
LogUtils . d ( TAG , " 保存位置 posId= " + posId + " 新备注= " + newMemo + " 距离启用= " + isDistanceEnable ) ;
}
}
} ) ;
} ) ;
}
}
// =========================================================================
// =========================================================================
// PositionTaskListView 集成(强化复用逻辑:复用后重新同步服务数据,确保数据不丢失)
// PositionTaskListView 集成
// =========================================================================
// =========================================================================
/**
private void initAndBindSimpleTaskView ( PositionTaskListView taskView , String posId , MainService mainService ) {
* 初始化+绑定简单模式任务列表视图——复用后重新执行,从服务同步最新任务
LogUtils . d ( TAG , " initAndBindSimpleTaskView posId= " + posId ) ;
*/
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 ) {
LogUtils . w ( TAG , " 初始化简单模式 任务视图失败:参数无效( posId=" + posId + " , service=" + mainService + " ) " ) ;
LogUtils . w ( TAG , " 初始化简单任务视图失败:参数无效 " ) ;
return ;
return ;
}
}
// 1. 初始化任务视图( 绑定MainService+当前位置ID——复用后重新绑定, 确保服务引用有效)
taskView . init ( mainService , posId ) ;
taskView . init ( mainService , posId ) ;
// 2. 设置为简单模式(仅展示,隐藏编辑按钮——复用后恢复视图模式)
taskView . setViewStatus ( PositionTaskListView . VIEW_MODE_SIMPLE ) ;
taskView . setViewStatus ( PositionTaskListView . VIEW_MODE_SIMPLE ) ;
// 3. 关键:复用后强制从服务同步最新任务(避免显示旧数据,核心修复点)
taskView . syncTasksFromMainService ( ) ;
taskView . syncTasksFromMainService ( ) ;
// 4. 任务更新回调(服务任务变化时重新同步——复用后重新绑定回调,避免监听失效)
taskView . setOnTaskUpdatedListener ( new PositionTaskListView . OnTaskUpdatedListener ( ) {
taskView . setOnTaskUpdatedListener ( new PositionTaskListView . OnTaskUpdatedListener ( ) {
@Override
@Override
public void onTaskUpdated ( String positionId , ArrayList updatedTasks ) {
public void onTaskUpdated ( String positionId , ArrayList updatedTasks ) {
LogUtils . d ( TAG , " 简单模式任务更新: 位置ID = " + positionId + " ,已启用 任务数=" + updatedTasks . size ( ) ) ;
LogUtils . d ( TAG , " 简单模式任务更新 posId = " + positionId + " 任务数=" + updatedTasks . size ( ) ) ;
}
}
} ) ;
} ) ;
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 ) {
LogUtils . d ( TAG , " initAndBindEditTaskView posId= " + posId ) ;
if ( taskView = = null | | TextUtils . isEmpty ( posId ) | | mainService = = null | | btnAddTask = = null ) {
if ( taskView = = null | | TextUtils . isEmpty ( posId ) | | mainService = = null | | btnAddTask = = null ) {
LogUtils . w ( TAG , " 初始化编辑模式 任务视图失败:参数无效( posId=" + posId + " , btnAddTask=" + btnAddTask + " ) " ) ;
LogUtils . w ( TAG , " 初始化编辑任务视图失败:参数无效 " ) ;
return ;
return ;
}
}
// 1. 初始化任务视图( 绑定MainService+当前位置ID——复用后重新绑定, 确保服务引用有效)
taskView . init ( mainService , posId ) ;
taskView . init ( mainService , posId ) ;
// 2. 设置为编辑模式(显示编辑/删除按钮——复用后恢复视图模式)
taskView . setViewStatus ( PositionTaskListView . VIEW_MODE_EDIT ) ;
taskView . setViewStatus ( PositionTaskListView . VIEW_MODE_EDIT ) ;
// 3. 关键:复用后强制从服务同步最新任务(避免显示旧数据,核心修复点)
taskView . syncTasksFromMainService ( ) ;
taskView . syncTasksFromMainService ( ) ; // 4. 绑定“新增任务”按钮逻辑(复用后重新绑定点击事件,避免按钮点击失效)
btnAddTask . setOnClickListener ( new View . OnClickListener ( ) {
btnAddTask . setOnClickListener ( new View . OnClickListener ( ) {
@Override
@Override
public void onClick ( View v ) {
public void onClick ( View v ) {
// 构建默认任务模型( 关联当前位置ID, 使用默认配置)
PositionTaskModel newTask = new PositionTaskModel ( ) ;
PositionTaskModel newTask = new PositionTaskModel ( ) ;
newTask . setTaskId ( PositionTaskModel . genTaskId ( ) ) ; // 生成唯一任务ID( 需模型类实现)
newTask . setTaskId ( PositionTaskModel . genTaskId ( ) ) ;
newTask . setPositionId ( posId ) ; // 绑定当前位置
newTask . setPositionId ( posId ) ;
newTask . setTaskDescription ( DEFAULT_TASK_DESC ) ; // 默认描述
newTask . setTaskDescription ( DEFAULT_TASK_DESC ) ;
newTask . setDiscussDistance ( DEFAULT_TASK_DISTANCE ) ; // 默认触发距离( 50米)
newTask . setDiscussDistance ( DEFAULT_TASK_DISTANCE ) ;
newTask . setIsEnable ( true ) ; // 默认启用
newTask . setIsEnable ( true ) ;
newTask . setIsBingo ( false ) ; // 初始未触发// 调用任务视图的新增方法( 假设视图已实现addNewTask, 内部同步MainService)
newTask . setIsBingo ( false ) ;
taskView . addNewTask ( newTask ) ;
taskView . addNewTask ( newTask ) ;
hideSoftKeyboard ( v ) ; // 隐藏软键盘,提升体验
hideSoftKeyboard ( v ) ;
LogUtils . d ( TAG , " 编辑模式新增任务: 位置ID =" + posId + " , 任务ID =" + newTask . getTaskId ( ) ) ;
LogUtils . d ( TAG , " 新增任务 posId =" + posId + " taskId =" + newTask . getTaskId ( ) ) ;
}
}
} ) ; // 5. 任务更新回调(通知外部任务变化——复用后重新绑定回调,确保交互正常)
} ) ;
taskView . setOnTaskUpdatedListener ( new PositionTaskListView . OnTaskUpdatedListener ( ) {
taskView . setOnTaskUpdatedListener ( new PositionTaskListView . OnTaskUpdatedListener ( ) {
@Override
@Override
public void onTaskUpdated ( String positionId , ArrayList updatedTasks ) {
public void onTaskUpdated ( String positionId , ArrayList updatedTasks ) {
LogUtils . d ( TAG , " 编辑模式任务更新: 位置ID = " + positionId + " ,当前 任务数=" + updatedTasks . size ( ) ) ;
LogUtils . d ( TAG , " 编辑模式任务更新 posId = " + positionId + " 任务数=" + updatedTasks . size ( ) ) ;
}
}
} ) ;
} ) ;
LogUtils . d ( TAG , " 初始化/复用编辑模式任务视图完成: 位置ID= " + posId ) ;
}
}
// =========================================================================
// =========================================================================
// 工具方法(保留原有逻辑,适配资源复用场景)
// 工具方法
// =========================================================================
// =========================================================================
/**
- 更新距离显示(复用后重新执行,确保显示最新距离+颜色——适配资源复用)
*/
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 , " updateDistanceDisplay: 参数为空 " ) ;
return ;
return ;
} // 场景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标记失败状态)
}
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: 正常显示距离( 按距离范围设置颜色——复用后重新计算颜色)
}
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 ) ) ;
} else if ( distance < = 500 ) {
} else if ( distance < = 500 ) {
distanceView . setTextColor ( mContext . getResources ( ) . getColor ( R . color . yellow ) ) ; // 中距离( ≤500米)
distanceView . setTextColor ( mContext . getResources ( ) . getColor ( R . color . yellow ) ) ;
} else {
} else {
distanceView . setTextColor ( mContext . getResources ( ) . getColor ( R . color . red ) ) ; // 远距离(>500米)
distanceView . setTextColor ( mContext . getResources ( ) . getColor ( R . color . red ) ) ;
}
}
}
}
/**
- 根据索引获取位置模型(容错处理,避免越界/空指针——适配复用后索引变化场景)
*/
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 ( ) ) {
LogUtils . w ( TAG , " 获取位置模型失败:无效索引( " + index + " )或缓存为空 " ) ;
LogUtils . w ( TAG , " getPositionByIndex: 无效索引 index= " + index ) ;
return null ;
return null ;
}
}
return mCachedPositionList . get ( index ) ;
return mCachedPositionList . get ( index ) ;
}
}
/**
- 根据位置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 , " getPositionIndexById: 参数无效 " ) ;
return - 1 ;
return - 1 ;
} // 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 ( ) ) ) {
return i ;
return i ;
}
}
}
}
LogUtils . w ( TAG , " 获取位置索引失败: 未找到ID=" + positionId ) ;
LogUtils . w ( TAG , " 未找到位置 ID= " + positionId ) ;
return - 1 ;
return - 1 ;
}
}
/**
- 局部更新距离UI( 仅更新指定位置的距离, 避免全量刷新卡顿——适配复用后控件缓存有效场景)
*/
public void updateSinglePositionDistance ( String positionId ) {
public void updateSinglePositionDistance ( String positionId ) {
LogUtils . d ( TAG , " updateSinglePositionDistance posId= " + positionId ) ;
if ( TextUtils . isEmpty ( positionId ) | | mPosDistanceViewMap . isEmpty ( ) ) {
if ( TextUtils . isEmpty ( positionId ) | | mPosDistanceViewMap . isEmpty ( ) ) {
LogUtils . w ( TAG , " 局部更新距离失败: ID无效或无控件缓存( ID= " + positionId + " ) " ) ;
return ;
return ;
}
}
// 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 servicePosList = mainService . getPositionList ( ) ;
ArrayList servicePosList = mainService . getPositionList ( ) ;
if ( servicePosList ! = null & & ! servicePosList . isEmpty ( ) ) {
if ( servicePosList ! = null & & ! servicePosList . isEmpty ( ) ) {
// Java 7 迭代器遍历, 避免ConcurrentModificationException
Iterator iter = servicePosList . iterator ( ) ;
Iterator iter = servicePosList . iterator ( ) ;
while ( iter . hasNext ( ) ) {
while ( iter . hasNext ( ) ) {
PositionModel pos = ( PositionModel ) iter . next ( ) ;
PositionModel pos = ( PositionModel ) iter . next ( ) ;
@@ -474,13 +407,13 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
}
}
} catch ( Exception e ) {
} catch ( Exception e ) {
LogUtils . d ( TAG , " 获取最新 位置数据失败( ID= " + positionId + " ) " + e ) ;
LogUtils . e ( TAG , " 获取位置数据异常 " , e ) ;
return ;
return ;
} if ( latestPos = = null ) {
}
LogUtils . w ( TAG , " 局部更新距离失败: 未找到位置ID= " + positionId ) ;
if ( latestPos = = null ) {
LogUtils . w ( TAG , " 未找到位置 posId= " + positionId ) ;
return ;
return ;
}
}
// 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 ;
@@ -490,146 +423,130 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
updateDistanceDisplay ( distanceView , finalLatestPos ) ;
updateDistanceDisplay ( distanceView , finalLatestPos ) ;
}
}
} ) ;
} ) ;
LogUtils . d ( TAG , " 局部更新距离完成: 位置ID= " + positionId + " ,距离= " + latestPos . getRealPositionDistance ( ) + " 米 " ) ;
} else {
} else {
mPosDistanceViewMap . remove ( positionId ) ; // 移除无效控件缓存(如视图已被销毁)
mPosDistanceViewMap . remove ( positionId ) ;
LogUtils . w ( TAG , " 局部更新距离失败:控件已回收/脱离视图树( ID= " + positionId + " ) " ) ;
}
}
}
}
/**
- 全量更新位置数据(从服务同步最新数据,过滤无效/重复项——适配复用后全量刷新场景)
*/
public void updateAllPositionData ( ArrayList < PositionModel > newPosList ) {
public void updateAllPositionData ( ArrayList < PositionModel > newPosList ) {
LogUtils . d ( TAG , " updateAllPositionData 新数据数量= " + ( newPosList ! = null ? newPosList . size ( ) : 0 ) ) ;
if ( newPosList = = null ) {
if ( newPosList = = null ) {
LogUtils . w ( TAG , " 全量更新位置数据失败:新列表为空 " ) ;
return ;
return ;
}
}
// 1. 过滤无效位置( 校验核心字段: ID/经纬度合法)
ArrayList < PositionModel > validPosList = new ArrayList < PositionModel > ( ) ;
ArrayList < PositionModel > validPosList = new ArrayList < PositionModel > ( ) ;
for ( PositionModel pos : newPosList ) {
for ( PositionModel pos : newPosList ) {
if ( TextUtils . isEmpty ( pos . getPositionId ( ) )
if ( TextUtils . isEmpty ( pos . getPositionId ( ) )
| | pos . getLongitude ( ) < - 180 | | pos . getLongitude ( ) > 180
| | pos . getLongitude ( ) < - 180 | | pos . getLongitude ( ) > 180
| | pos . getLatitude ( ) < - 90 | | pos . getLatitude ( ) > 90 ) {
| | pos . getLatitude ( ) < - 90 | | pos . getLatitude ( ) > 90 ) {
LogUtils . w ( TAG , " 过滤无效位置: ID= " + pos . getPositionId ( ) + " (经纬度/ID非法) " ) ;
continue ;
continue ;
}
}
validPosList . add ( pos ) ;
validPosList . add ( pos ) ;
}
}
// 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 ) ;
}
}
ArrayList uniquePosList = new ArrayList ( uniquePosMap . values ( ) ) ; // 3. 同步到本地缓存+刷新UI( 刷新后触发onBind, 自动重新绑定资源)
ArrayList uniquePosList = new ArrayList ( uniquePosMap . values ( ) ) ;
this . mCachedPositionList . clear ( ) ;
this . mCachedPositionList. addAll ( uniquePosList ) ;
mCachedPositionList. clear ( ) ;
// 清空旧控件缓存(避免引用失效数据,刷新后重新缓存新控件)
mCachedPositionList . addAll ( uniquePosList ) ;
mPosDistanceViewMap . clear ( ) ;
mPosDistanceViewMap . clear ( ) ;
mSimpleTaskViewMap . clear ( ) ;
mSimpleTaskViewMap . clear ( ) ;
mEditTaskViewMap . clear ( ) ;
mEditTaskViewMap . clear ( ) ;
notifyDataSetChanged ( ) ;
notifyDataSetChanged ( ) ;
LogUtils . d ( TAG , " 全量更新位置数据完成:原数量= " + newPosList . size ( ) + " ,过滤后= " + uniquePosList . size ( ) ) ;
LogUtils . d ( TAG , " 全量更新完成,有效数量= " + uniquePosList . size ( ) ) ;
}
}
/**
- 隐藏软键盘(编辑完成后调用,提升用户体验——适配复用后软键盘残留问题)
*/
private void hideSoftKeyboard ( View view ) {
private void hideSoftKeyboard ( View view ) {
if ( mContext = = null | | view = = null ) {
if ( mContext = = null | | view = = null ) {
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次——适配复用后服务引用失效场景)
*/
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, 避免频繁重试
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 ) {
LogUtils . d ( TAG , " 重试获取服务时线程 被中断 " + e ) ;
LogUtils . e ( TAG , " 重试被中断 " , e ) ;
Thread . currentThread ( ) . interrupt ( ) ; // 恢复中断状态
Thread . currentThread ( ) . interrupt ( ) ;
break ;
break ;
}
}
} LogUtils . e ( TAG , " 重试 " + retryCount + " 次后仍未获取到MainService " ) ;
}
LogUtils . e ( TAG , " 重试 " + retryCount + " 次仍未获取到 MainService " ) ;
return null ;
return null ;
}
}
// =========================================================================
// =========================================================================
// 实现 MainService.TaskUpdateListener 接口(服务任务变化时回调——适配复用后任务同步)
// 任务更新监听
// =========================================================================
// =========================================================================
@Override
@Override
public void onTaskUpdated ( ) {
public void onTaskUpdated ( ) {
LogUtils . d ( TAG , " 收到MainService任务更新通知, 同步所有任务列表视图( 含复用视图) " ) ;
LogUtils . d ( TAG , " onTaskUpdated: 收到服务任务更新 " ) ;
// 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. 同步编辑模式任务视图(支持编辑的全量任务——适配复用后视图已重新缓存)
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 ( ) ;
}
}
}
}
}
}
}
}
// =========================================================================
// =========================================================================
// 回调设置方法( 供Activity绑定交互逻辑——适配复用后回调不失效)
// 外部 回调设置
// =========================================================================
// =========================================================================
public void setOnDeleteClickListener ( OnDeleteClickListener listener ) {
public void setOnDeleteClickListener ( OnDeleteClickListener listener ) {
LogUtils . d ( TAG , " setOnDeleteClickListener listener= " + listener ) ;
this . mOnDeleteListener = listener ;
this . mOnDeleteListener = listener ;
}
}
public void setOnSavePositionClickListener ( OnSavePositionClickListener listener ) {
public void setOnSavePositionClickListener ( OnSavePositionClickListener listener ) {
LogUtils . d ( TAG , " setOnSavePositionClickListener listener= " + listener ) ;
this . mOnSavePosListener = listener ;
this . mOnSavePosListener = listener ;
}
}
// =========================================================================
// =========================================================================
// 资源释放( Activity销毁时调用, 彻底释放引用, 避免内存泄漏——保留原有安全逻辑)
// 资源释放
// =========================================================================
// =========================================================================
public void release ( ) {
public void release ( ) {
// 1. 反注册MainService任务监听( 解除服务绑定)
LogUtils . d ( TAG , " release: 开始释放 Adapter 资源 " ) ;
MainService mainService = mMainServiceRef . get ( ) ;
MainService mainService = mMainServiceRef . get ( ) ;
if ( mainService ! = null ) {
if ( mainService ! = null ) {
mainService . unregisterTaskUpdateListener ( this ) ;
mainService . unregisterTaskUpdateListener ( this ) ;
LogUtils . d ( TAG , " 已反注册MainService 任务监听 " ) ;
LogUtils . d ( TAG , " 已反注册任务监听 " ) ;
}
}
// 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 ( ) ) {
@@ -642,7 +559,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
}
}
// 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 ( ) ) {
@@ -655,7 +571,6 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
}
}
// 4. 清空其他缓存+置空引用(彻底释放,避免内存泄漏)
mPosDistanceViewMap . clear ( ) ;
mPosDistanceViewMap . clear ( ) ;
if ( mCachedPositionList ! = null ) {
if ( mCachedPositionList ! = null ) {
mCachedPositionList . clear ( ) ;
mCachedPositionList . clear ( ) ;
@@ -663,24 +578,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
mOnDeleteListener = null ;
mOnDeleteListener = null ;
mOnSavePosListener = null ;
mOnSavePosListener = null ;
LogUtils . d ( TAG , " Adapter资源已完全释放( 任务视图资源释放+缓存清空+引用置空) " ) ;
LogUtils . d ( TAG , " release: 资源释放完成 " ) ;
}
}
// =========================================================================
// =========================================================================
// 静态内部类: ViewHolder(与布局严格对应,避免外部引用导致内存泄漏)
// ViewHolder
// =========================================================================
// =========================================================================
/**
- 简单模式ViewHolder( 对应 item_position_simple.xml, 含简单模式任务列表视图)
*/
public static class SimpleViewHolder extends RecyclerView . ViewHolder {
public static class SimpleViewHolder extends RecyclerView . ViewHolder {
TextView tvSimpleLon ; // 经度显示
TextView tvSimpleLon ;
TextView tvSimpleLat ; // 纬度显示
TextView tvSimpleLat ;
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严格一致, 避免运行时空指针)
tvSimpleLon = ( TextView ) itemView . findViewById ( R . id . tv_simple_longitude ) ;
tvSimpleLon = ( TextView ) itemView . findViewById ( R . id . tv_simple_longitude ) ;
tvSimpleLat = ( TextView ) itemView . findViewById ( R . id . tv_simple_latitude ) ;
tvSimpleLat = ( TextView ) itemView . findViewById ( R . id . tv_simple_latitude ) ;
tvSimpleMemo = ( TextView ) itemView . findViewById ( R . id . tv_simple_memo ) ;
tvSimpleMemo = ( TextView ) itemView . findViewById ( R . id . tv_simple_memo ) ;
@@ -689,24 +601,21 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
}
}
/**
- 编辑模式ViewHolder( 对应 item_position_edit.xml, 含编辑模式任务列表视图)
*/
public static class EditViewHolder extends RecyclerView . ViewHolder {
public static class EditViewHolder extends RecyclerView . ViewHolder {
TextView tvEditLon ; // 经度显示(不可编辑)
TextView tvEditLon ;
TextView tvEditLat ; // 纬度显示(不可编辑)
TextView tvEditLat ;
EditText etEditMemo ; // 备注编辑
EditText etEditMemo ;
TextView tvEditDistance ; // 距离显示
TextView tvEditDistance ;
RadioGroup rgDistanceSwitch ; // 距离启用/禁用开关
RadioGroup rgDistanceSwitch ;
Button btnCancel ; // 取消编辑按钮
Button btnCancel ;
Button btnDelete ; // 删除位置按钮
Button btnDelete ;
Button btnSave ; // 保存位置按钮
Button btnSave ;
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严格一致, 避免运行时空指针)
tvEditLon = ( TextView ) itemView . findViewById ( R . id . tv_edit_longitude ) ;
tvEditLon = ( TextView ) itemView . findViewById ( R . id . tv_edit_longitude ) ;
tvEditLat = ( TextView ) itemView . findViewById ( R . id . tv_edit_latitude ) ;
tvEditLat = ( TextView ) itemView . findViewById ( R . id . tv_edit_latitude ) ;
etEditMemo = ( EditText ) itemView . findViewById ( R . id . et_edit_memo ) ;
etEditMemo = ( EditText ) itemView . findViewById ( R . id . et_edit_memo ) ;
@@ -722,88 +631,9 @@ public class PositionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
}
}
// =========================================================================
// =========================================================================
// 补充: PositionTaskListView 必要方法适配(确保视图类已实现以下基础 方法)
// 方法说明类(保留不动 )
// (若视图类未实现,需在 PositionTaskListView 中添加对应逻辑,否则复用后功能异常)
// =========================================================================
// =========================================================================
public static class PositionTaskListViewRequiredMethods {
public static class PositionTaskListViewRequiredMethods {
/**
1. - init 方法:初始化任务视图(绑定服务+位置ID——复用后重新绑定, 确保服务引用有效)
- 需在 PositionTaskListView 中添加:
- public void init(MainService mainService, String positionId) {
- this.mMainServiceRef = new WeakReference(mainService); // 弱引用服务,防泄漏
- this.mPositionId = positionId; // 绑定当前位置ID( 复用后更新为当前位置ID)
- }
*/
/**
2. - setViewStatus 方法:设置视图模式(简单/编辑——复用后恢复对应模式UI)
- 需在 PositionTaskListView 中添加:
- public static final int VIEW_MODE_SIMPLE = 0; // 仅显示(隐藏编辑/删除按钮)
- public static final int VIEW_MODE_EDIT = 1; // 可编辑(显示编辑/删除按钮)
- private int mViewMode;
- public void setViewStatus(int viewMode) {
- this.mViewMode = viewMode;
- // 根据模式控制按钮显示:简单模式隐藏编辑按钮,编辑模式显示
- 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 方法:从服务同步任务数据(复用后核心方法,避免旧数据)
- 需在 PositionTaskListView 中添加:
- public void syncTasksFromMainService() {
- MainService mainService = mMainServiceRef.get();
- if (mainService == null || TextUtils.isEmpty(mPositionId)) return;
- // 根据视图模式拉取对应任务:简单模式仅拉已启用,编辑模式拉全部
- ArrayList tasks = (mViewMode == VIEW_MODE_SIMPLE)
- ? mainService.getEnabledTasksByPositionId(mPositionId)
- : mainService.getTasksByPositionId(mPositionId);
- // 更新列表数据( 刷新UI, 确保复用后显示最新任务)
- if (mTaskAdapter != null) {
- mTaskAdapter.setTaskList(tasks);
- mTaskAdapter.notifyDataSetChanged();
- }
- // 通知外部任务更新( 如Adapter需要联动)
- if (mTaskUpdateListener != null) mTaskUpdateListener.onTaskUpdated(mPositionId, tasks);
- }
*/
/**
4. - addNewTask 方法:新增任务(同步服务+刷新列表——复用后功能正常)
- 需在 PositionTaskListView 中添加:
- public void addNewTask(PositionTaskModel newTask) {
- if (newTask == null || TextUtils.isEmpty(newTask.getPositionId())) return;
- MainService mainService = mMainServiceRef.get();
- if (mainService != null) {
- mainService.addTask(newTask); // 同步到服务(确保数据持久化)
- syncTasksFromMainService(); // 新增后立即同步,刷新列表
- Toast.makeText(getContext(), "任务新增成功", Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(getContext(), "服务未就绪,新增失败", Toast.LENGTH_SHORT).show();
- }
- }
*/
/**
5. - clearData 方法: 清空任务数据( 仅在Activity销毁时调用, 不复用场景)
- 需在 PositionTaskListView 中添加:
- public void clearData() {
- if (mTaskList != null) mTaskList.clear(); // 清空本地任务列表
- if (mTaskAdapter != null) mTaskAdapter.notifyDataSetChanged(); // 刷新空UI
- }
*/
/**
6. - setOnTaskUpdatedListener 方法:设置任务更新回调(复用后重新绑定,避免回调失效)
- 需在 PositionTaskListView 中添加:
- public interface OnTaskUpdatedListener {
- void onTaskUpdated(String positionId, ArrayList updatedTasks);
- }
- private OnTaskUpdatedListener mTaskUpdateListener;
- public void setOnTaskUpdatedListener(OnTaskUpdatedListener listener) {
- this.mTaskUpdateListener = listener;
- }
*/
}
}
}
}