@@ -1,10 +1,12 @@
package cc.winboll.studio.positions.views ;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/09/30 08:09
* @Describe 位置任务列表视图( 适配MainService唯一数据源+同步任务状态+支持简单/编辑模式)
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
* @CreateTime 2025-09-30 08:09:00
* @EditTime 2026-03-31 19:00:00
*/
import android.content.Context ;
import android.util.AttributeSet ;
import android.view.LayoutInflater ;
@@ -21,6 +23,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable ;
import androidx.recyclerview.widget.LinearLayoutManager ;
import androidx.recyclerview.widget.RecyclerView ;
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog ;
import cc.winboll.studio.libappbase.LogUtils ;
import cc.winboll.studio.positions.R ;
import cc.winboll.studio.positions.models.PositionTaskModel ;
@@ -35,101 +38,96 @@ import java.util.List;
import java.util.Locale ;
public class PositionTaskListView extends LinearLayout {
// 视图模式常量
public static final int VIEW_MODE_SIMPLE = 1 ;
public static final int VIEW_MODE_EDIT = 2 ;
// 核心成员变量( 新增MainService引用, 作为唯一数据源)
private static final String TAG = " PositionTaskListView " ;
// 核心成员变量
private String mBindPositionId ;
private MainService mMainService ; // 持有MainService实例, 所有任务数据从服务获取
private MainService mMainService ;
private int mCurrentViewMode ;
private TaskListAdapter mTaskAdapter ;
private RecyclerView mRvTasks ;
// 任务修改回调接口( 保留, 用于通知外部同步UI)
// 任务修改回调接口
public interface OnTaskUpdatedListener {
void onTaskUpdated ( String positionId , ArrayList < PositionTaskModel > updatedTasks ) ;
}
private OnTaskUpdatedListener mOnTaskUpdatedListener ;
// ---------------------- 构造函数( 不变, 新增MainService空校验) ----------------------
// ---------------------- 构造函数 ----------------------
public PositionTaskListView ( Context context ) {
super ( context ) ;
LogUtils . d ( TAG , " PositionTaskListView 构造函数 1 参数: context= " + context ) ;
initView ( context ) ;
}
public PositionTaskListView ( Context context , @Nullable AttributeSet attrs ) {
super ( context , attrs ) ;
LogUtils . d ( TAG , " PositionTaskListView 构造函数 2 参数: context= " + context + " , attrs= " + attrs ) ;
initView ( context ) ;
}
public PositionTaskListView ( Context context , @Nullable AttributeSet attrs , int defStyleAttr ) {
super ( context , attrs , defStyleAttr ) ;
LogUtils . d ( TAG , " PositionTaskListView 构造函数 3 参数: context= " + context + " , attrs= " + attrs + " , defStyleAttr= " + defStyleAttr ) ;
initView ( context ) ;
}
// 初始化视图(绑定控件+设置布局, Adapter初始化为空数据)
// ---------------------- 初始化视图 ----------------------
private void initView ( Context context ) {
LogUtils . d ( TAG , " initView 开始执行 参数: context= " + context ) ;
setOrientation ( VERTICAL ) ;
LayoutInflater . from ( context ) . inflate ( R . layout . view_position_task_list , this , true ) ;
mRvTasks = ( RecyclerView ) findViewById ( R . id . rv_position_tasks ) ;
mRvTasks . setLayoutManager ( new LinearLayoutManager ( context ) ) ;
// 初始化为空列表( 数据后续从MainService同步)
mTaskAdapter = new TaskListAdapter ( new ArrayList < PositionTaskModel > ( ) ) ;
mRvTasks . setAdapter ( mTaskAdapter ) ;
mCurrentViewMode = VIEW_MODE_SIMPLE ;
LogUtils . d ( TAG , " 视图初始化完成( 等待绑定MainService和位置ID) " ) ;
LogUtils . d ( TAG , " initView 执行完成,视图初始化完毕 " ) ;
}
// ---------------------- 对外API( 核心调整: 绑定MainService+从服务同步数据) ----------------------
/**
* 初始化: 绑定MainService+关联位置ID( 必须先调用此方法, 否则无数据)
* @param mainService MainService实例( 从Activity传入, 确保唯一数据源)
* @param positionId 关联的位置ID( 只加载该位置下的任务)
*/
// ---------------------- 对外API ----------------------
public void init ( MainService mainService , String positionId ) {
LogUtils . d ( TAG , " init 开始执行 参数: mainService= " + mainService + " , positionId= " + positionId ) ;
if ( mainService = = null ) {
LogUtils . e ( TAG , " init失败: MainService实例为空( 需从Activity传入有效服务实例) " ) ;
LogUtils . e ( TAG , " init 失败: MainService 为空 " ) ;
showToast ( " 任务列表初始化失败:服务未就绪 " ) ;
return ;
}
if ( positionId = = null | | positionId . trim ( ) . isEmpty ( ) ) {
LogUtils . e ( TAG , " init失败: 位置ID为空( 需关联有效位置) " ) ;
LogUtils . e ( TAG , " init 失败:positionId 为空 " ) ;
showToast ( " 任务列表初始化失败:未关联位置 " ) ;
return ;
}
// 绑定服务实例+位置ID
this . mMainService = mainService ;
this . mBindP ositionId = positionId ;
LogUtils . d ( TAG , " 已绑定MainService和位置ID: " + positionId ) ;
mMainService = mainService ;
mBindPositionId = positionId ;
LogUtils . d ( TAG , " init 绑定成功: p ositionId= " + positionId ) ;
// 从MainService同步当前位置的任务( 核心: 数据来源改为服务)
syncTasksFromMainService ( ) ;
LogUtils . d ( TAG , " init 执行完成 " ) ;
}
/**
* 从MainService同步当前位置的任务( 核心方法, 所有数据加载入口)
* 作用: 1. 清空本地缓存→2. 从服务获取全量任务→3. 筛选当前位置任务→4. 刷新Adapter
*/
public void syncTasksFromMainService ( ) {
// 安全校验(服务未绑定/位置ID为空, 不执行同步)
LogUtils . d ( TAG , " syncTasksFromMainService 开始执行 " ) ;
if ( mMainService = = null | | mBindPositionId = = null | | mBindPositionId . trim ( ) . isEmpty ( ) ) {
LogUtils . w ( TAG , " 同步任务失败: MainService未绑定 或位置ID无效" ) ;
LogUtils . w ( TAG , " syncTasksFrom MainService 失败:服务 或位置ID无效" ) ;
return ;
}
try {
// 1. 从MainService获取全量任务( 服务是唯一数据源, 避免本地缓存不一致)
ArrayList < PositionTaskModel > allServiceTasks = mMainService . getAllTasks ( ) ;
LogUtils . d ( TAG , " 从MainService获取全量任务数: " + ( allServiceTasks = = null ? 0 : allServiceTasks . size ( ) ) ) ;
LogUtils . d ( TAG , " syncTasksFromMainService 从服务获取任务总数: " + ( allServiceTasks = = null ? 0 : allServiceTasks . size ( ) ) ) ;
// 2. 筛选当前位置关联的任务( 只保留与mBindPositionId匹配的任务)
ArrayList < PositionTaskModel > currentPosTasks = new ArrayList < PositionTaskModel > ( ) ;
ArrayList < PositionTaskModel > currentPosTasks = new ArrayList < > ( ) ;
if ( allServiceTasks ! = null & & ! allServiceTasks . isEmpty ( ) ) {
for ( PositionTaskModel task : allServiceTasks ) {
if ( isTaskMatchedWithPosition ( task ) ) {
@@ -137,144 +135,148 @@ public class PositionTaskListView extends LinearLayout {
}
}
}
LogUtils . d ( TAG , " 筛选后当前位置任务数: " + currentPosTasks . size ( ) ) ;
LogUtils . d ( TAG , " syncTasksFromMainService 筛选后当前位置任务数: " + currentPosTasks . size ( ) ) ;
// 3. 更新Adapter数据( 直接替换数据源, 避免本地缓存)
mTaskAdapter . updateData ( currentPosTasks ) ;
LogUtils . d ( TAG , " 从 MainService同步任务 完成( Adapter已刷新) " ) ;
LogUtils . d ( TAG , " syncTasksFrom MainService 执行 完成, Adapter已刷新" ) ;
} catch ( Exception e ) {
LogUtils . d ( TAG , " 同步任务失败( MainService调用异常): " + e . getMessage ( ) ) ;
LogUtils . e ( TAG , " syncTasksFrom MainService 异常: " + e . getMessage ( ) , e );
showToast ( " 任务同步失败,请重试 " ) ;
}
}
// 视图模式切换( 不变, 刷新Adapter触发视图类型变更)
public void setViewStatus ( int viewMode ) {
LogUtils . d ( TAG , " setViewStatus 参数: viewMode= " + viewMode ) ;
if ( viewMode ! = VIEW_MODE_SIMPLE & & viewMode ! = VIEW_MODE_EDIT ) {
LogUtils . w ( TAG , " 设置视图模式失败:无效模式(仅支持简单/编辑模式) " ) ;
LogUtils . w ( TAG , " setViewStatus 无效模式 " ) ;
return ;
}
mCurrentViewMode = viewMode ;
mTaskAdapter . notifyDataSetChanged ( ) ;
LogUtils . d ( TAG , " 已切换视图模式: " + ( viewMode = = VIEW_MODE_SIMPLE ? " 简单模式 " : " 编辑模式 " ) ) ;
LogUtils . d ( TAG , " setViewStatus 切换完成: " + ( viewMode = = VIEW_MODE_SIMPLE ? " 简单模式 " : " 编辑模式 " ) ) ;
}
// 保留回调接口( 用于通知外部UI刷新, 如Activity更新列表)
public void setOnTaskUpdatedListener ( OnTaskUpdatedListener listener ) {
this . m OnTaskUpdatedListener = listener ;
LogUtils . d ( TAG , " 已设置任务更新回调监听 " ) ;
LogUtils . d ( TAG , " set OnTaskUpdatedListener 参数: listener= " + listener ) ;
mOnTaskUpdatedListener = listener ;
}
/**
* 获取当前位置的任务( 从Adapter数据源获取, 而非本地缓存)
* @return 当前位置任务列表(新集合,避免外部修改数据源)
*/
public ArrayList < PositionTaskModel > getCurrentPosTasks ( ) {
return new ArrayList < PositionTaskModel > ( mTaskAdapter . getAdapterData ( ) ) ;
LogUtils . d ( TAG , " getCurrentPosTasks 被调用 " ) ;
return new ArrayList < > ( mTaskAdapter . getAdapterData ( ) ) ;
}
/**
* 清空数据(解绑服务+清空位置ID+重置Adapter)
* 场景:视图销毁/切换位置时调用,避免数据残留
*/
public void clearData ( ) {
// 1. 清空Adapter数据源
LogUtils . d ( TAG , " clearData 开始执行 " ) ;
mTaskAdapter . updateData ( new ArrayList < PositionTaskModel > ( ) ) ;
// 2. 解绑服务+位置ID( 避免下次使用时引用旧数据)
this . mMainService = null ;
this . mBindPositionId = null ;
// 3. 重置视图模式
mMainService = null ;
mBindPositionId = null ;
mCurrentViewMode = VIEW_MODE_SIMPLE ;
LogUtils . d ( TAG , " 数据已清空(解绑服务+重置视图) " ) ;
LogUtils . d ( TAG , " clearData 执行完成, 数据已清空" ) ;
}
/**
* 主动触发任务同步(强制从服务拉取最新数据,刷新视图)
* 场景:外部操作后(如新增任务),调用此方法更新列表
*/
public void triggerTaskSync ( ) {
LogUtils . d ( TAG , " 主动触发任务同步( 从MainService拉取最新数据) " ) ;
LogUtils . d ( TAG , " triggerTaskSync 主动触发同步 " ) ;
syncTasksFromMainService ( ) ;
// 通知外部( 如Activity) 任务已更新( 可选, 根据业务需求)
if ( mOnTaskUpdatedListener ! = null & & mBindPositionId ! = null ) {
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , getCurrentPosTasks ( ) ) ;
}
}
// ---------------------- 内部工具方法(新增服务空校验) ----------------------
private static final String TAG = " PositionTaskListView " ;
/**
* 校验任务是否与当前绑定的位置匹配
* @param task 待校验的任务
* @return true=匹配( 任务位置ID=当前绑定位置ID) , false=不匹配
*/
// ---------------------- 内部工具 ----------------------
private boolean isTaskMatchedWithPosition ( PositionTaskModel task ) {
if ( task = = null | | mBindPositionId = = null | | mBindPositionId . trim ( ) . isEmpty ( ) ) {
if ( task = = null | | mBindPositionId = = null ) {
return false ;
}
// 严格匹配任务的位置ID( 确保只加载当前位置的任务)
return mBindPositionId . equals ( task . getPositionId ( ) ) ;
}
/**
* 显示Toast( 简化调用, 避免重复代码)
*/
private void showToast ( String content ) {
if ( getContext ( ) = = null ) return ;
Toast . makeText ( getContext ( ) , content , Toast . LENGTH_SHORT ) . show ( ) ;
}
// ---------------------- 内部Adapter: 适配MainService数据源( 核心调整) ----------------------
private String genSelectedTimeText ( long timeMillis ) {
SimpleDateFormat sdf = new SimpleDateFormat ( " yyyy-MM-dd HH:mm " , Locale . getDefault ( ) ) ;
return sdf . format ( new Date ( timeMillis ) ) ;
}
// ---------------------- 外部新增任务 ----------------------
public void addNewTask ( PositionTaskModel newTask ) {
LogUtils . d ( TAG , " addNewTask 参数: newTask= " + newTask ) ;
if ( mMainService = = null ) {
LogUtils . e ( TAG , " addNewTask 失败: MainService为空 " ) ;
showToast ( " 新增任务失败:服务未就绪 " ) ;
return ;
}
if ( newTask = = null ) {
LogUtils . e ( TAG , " addNewTask 失败:任务为空 " ) ;
showToast ( " 新增任务失败:任务数据为空 " ) ;
return ;
}
if ( mBindPositionId = = null | | mBindPositionId . trim ( ) . isEmpty ( ) ) {
LogUtils . e ( TAG , " addNewTask 失败:未绑定位置 " ) ;
showToast ( " 新增任务失败:未关联位置 " ) ;
return ;
}
try {
newTask . setPositionId ( mBindPositionId ) ;
mMainService . addTask ( newTask ) ;
LogUtils . d ( TAG , " addNewTask 服务添加成功 taskId= " + newTask . getTaskId ( ) ) ;
syncTasksFromMainService ( ) ;
if ( mOnTaskUpdatedListener ! = null ) {
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , getCurrentPosTasks ( ) ) ;
}
showToast ( " 新增任务成功 " ) ;
} catch ( Exception e ) {
LogUtils . e ( TAG , " addNewTask 异常: " + e . getMessage ( ) , e ) ;
showToast ( " 新增失败,请重试 " ) ;
syncTasksFromMainService ( ) ;
}
}
// ---------------------- Adapter ----------------------
private class TaskListAdapter extends RecyclerView . Adapter < TaskListAdapter . TaskViewHolder > {
// Adapter数据源( 仅保留一份, 直接从MainService同步, 无本地冗余)
private List < PositionTaskModel > mAdapterData ;
// 初始化Adapter( 空数据源)
public TaskListAdapter ( List < PositionTaskModel > data ) {
this . mAdapterData = new ArrayList < PositionTaskModel > ( data ) ; // 防御性拷贝,避免外部修改
LogUtils . d ( TAG , " TaskListAdapter 构造 参数 data.size= " + data . size ( ) ) ;
mAdapterData = new ArrayList < > ( data ) ;
}
/**
* 更新Adapter数据源( 核心: 从MainService同步后调用, 替换数据源并刷新)
* @param newData 从MainService筛选后的当前位置任务列表
*/
public void updateData ( List < PositionTaskModel > newData ) {
LogUtils . d ( TAG , " updateData 参数 newData.size= " + ( newData = = null ? 0 : newData . size ( ) ) ) ;
if ( newData = = null ) {
this . mAdapterData. clear ( ) ;
mAdapterData. clear ( ) ;
} else {
this . mAdapterData = new ArrayList < PositionTaskModel > ( newData ) ; // 防御性拷贝
mAdapterData = new ArrayList < > ( newData ) ;
}
notifyDataSetChanged ( ) ; // 刷新列表(数据源已替换,确保显示最新数据)
notifyDataSetChanged ( ) ;
}
/**
* 获取Adapter当前数据源( 对外提供, 避免直接操作mAdapterData)
* @return 当前数据源(新集合,避免外部修改)
*/
public List < PositionTaskModel > getAdapterData ( ) {
return new ArrayList < PositionTaskModel > ( mAdapterData ) ;
return new ArrayList < > ( mAdapterData ) ;
}
// getItemCount: 空列表显示1个“空提示”项, 非空显示任务数
@Override
public int getItemCount ( ) {
return mAdapterData . isEmpty ( ) ? 1 : mAdapterData . size ( ) ;
}
// getItemViewType: 按“空列表/简单模式/编辑模式”区分视图类型(不变)
@Override
public int getItemViewType ( int position ) {
if ( mAdapterData . isEmpty ( ) ) {
return 0 ; // 0=空提示视图
return 0 ;
} else {
return mCurrentViewMode ; // 1=简单模式视图, 2=编辑模式视图
return mCurrentViewMode ;
}
}
// onCreateViewHolder: 按视图类型加载对应布局( 不变, 确保布局与模式匹配)
@NonNull
@Override
public TaskViewHolder onCreateViewHolder ( @NonNull ViewGroup parent , int viewType ) {
@@ -282,302 +284,230 @@ public class PositionTaskListView extends LinearLayout {
LayoutInflater inflater = LayoutInflater . from ( context ) ;
if ( viewType = = 0 ) {
// 空提示布局(无任务时显示)
View emptyView = inflater . inflate ( R . layout . item_task_empty , parent , false ) ;
return new EmptyViewHolder ( emptyView ) ;
} else if ( viewType = = VIEW_MODE_SIMPLE ) {
// 简单模式布局( 带isBingo红点, 仅展示)
Vi ew s impleTaskView = inflater . inflate ( R . layout . item_position_task_simple , parent , false ) ;
return new SimpleTaskViewHolder ( simpleTaskView ) ;
View simpleView = inflater . inflate ( R . layout . item_position_task_simple , parent , false ) ;
return n ew S impleTaskViewHolder ( simpleView ) ;
} else {
// 编辑模式布局(带编辑/删除按钮+启用开关,支持修改)
View editTaskView = inflater . inflate ( R . layout . item_task_content , parent , false ) ;
return new TaskContentViewHolder ( editTaskView ) ;
View editView = inflater . inflate ( R . layout . item_task_content , parent , false ) ;
return new TaskContentViewHolder ( editView ) ;
}
}
// onBindViewHolder: 按视图类型绑定数据( 核心调整: 操作后同步MainService)
@Override
public void onBindViewHolder ( @NonNull TaskViewHolder holder , int position ) {
// 1. 空提示视图绑定(根据模式显示不同提示文案)
if ( holder instanceof EmptyViewHolder ) {
EmptyViewHolder emptyHolder = ( EmptyViewHolder ) holder ;
TextView tvEmptyTip = emptyHolder . itemView . findViewById ( R . id . tv_task_empty_tip ) ;
tvEmptyTip . setText ( mCurrentViewMode = = VIEW_MODE_EDIT
? " 暂无任务,点击 \" 添加新任务 \" 创建 "
: " 暂无启用的任务 " ) ;
TextView tv = emptyHolder . itemView . findViewById ( R . id . tv_task_empty_tip ) ;
tv . setText ( mCurrentViewMode = = VIEW_MODE_EDIT
? " 暂无任务,点击 \" 添加新任务 \" 创建 "
: " 暂无启用的任务 " ) ;
return ;
}
// 2. 任务项有效性校验(避免越界/空数据)
if ( position > = mAdapterData . size ( ) ) {
LogUtils . w ( TAG , " 绑定任务数据失败:位置索引 越界( position=" + position + " ,数据量= " + mAdapterData . size ( ) + " ) " ) ;
LogUtils . w ( TAG , " onBindViewHolder 越界 position=" + position ) ;
return ;
}
final PositionTaskModel task = mAdapterData . get ( position ) ;
if ( task = = null ) {
LogUtils . w ( TAG , " 绑定任务数据失败:第 " + position + " 项任务为空 " ) ;
LogUtils . w ( TAG , " onBindViewHolder task为空 position= " + position ) ;
return ;
}
// 3. 简单模式绑定(仅展示,无修改操作,不变)
if ( holder instanceof SimpleTaskViewHolder ) {
SimpleTaskViewHolder simpleHolder = ( SimpleTaskViewHolder ) holder ;
// 任务描述
String taskDesc = task . g etTaskDescription ( ) = = null ? " 未设置描述 " : task . getTaskDescription ( ) ;
simpleHolder . tvSimpleTaskDesc . setText ( String . format ( " 任务:%s " , taskDesc ) ) ;
simpleHolder . tvStartTime . setText ( genSelectedTimeText ( task . getStartTime ( ) ) ) ;
// 距离条件(大于/小于+距离值)
String distanceCond = task . isGreaterThan ( ) ? " 大于 " : " 小于 " ;
simpleHolder . tvSimpleDistanceCond . setText ( String . format ( " 条件:距离 %s %d 米 " , distanceCond , task . getDiscussDistance ( ) ) ) ;
// 启用状态
simpleHolder . tvSimpleIsEnable . s etText ( task . isEnable ( ) ? " 状态:已启用 " : " 状态:已禁用 " ) ;
// 修改为从colors.xml读取颜色
simpleHolder . tvSimpleIsEnable . setTextColor ( task . isEnable ( )
? getContext ( ) . getResources ( ) . getColor ( R . color . colorEnableGreen )
: getContext ( ) . getResources ( ) . getColor ( R . color . colorGrayText ) ) ;
// isBingo红点( 任务触发时显示, 未触发时隐藏)
simpleHolder . vBingoDot . setVisibility ( task . isBingo ( ) ? View . VISIBLE : View . GONE ) ;
SimpleTaskViewHolder h = ( SimpleTaskViewHolder ) holder ;
String desc = task . getTaskDescription ( ) = = null ? " 未设置描述 " : task . getTaskDescription ( ) ;
h . tvSimpleTaskDesc . s etText ( String . format ( " 任务:%s " , desc ) ) ;
h . tvStartTime . setText ( genSelectedTimeText ( task . getStartTime ( ) ) ) ;
String cond = task . isGreaterThan ( ) ? " 大于 " : " 小于 " ;
h . tvSimpleDistanceCond . setText ( String . format ( " 条件:距离 %s %d 米 " , cond , task . getDiscussDistance ( ) ) ) ;
h . tvSimpleIsEnable . setText ( task . isEnable ( ) ? " 状态:已启用 " : " 状态:已禁用 " ) ;
h . tvSimpleIsEnable . setTextColor ( task . isEnable ( )
? getContext ( ) . getResources ( ) . getColor ( R . color . colorEnableGreen )
: getContext ( ) . getResources ( ) . g etColor ( R . color . colorGrayText ) ) ;
h . vBingoDot . setVisibility ( task . isBingo ( ) ? View . VISIBLE : View . GONE ) ;
} else if ( holder instanceof TaskContentViewHolder ) {
TaskContentViewHolder contentHolder = ( TaskContentViewHolder ) holder ;
bindEditModeTask ( contentHolder , task , position ) ;
TaskContentViewHolder h = ( TaskContentViewHolder ) holder ;
bindEditModeTask ( h , task , position ) ;
}
}
/**
* 编辑模式任务绑定( 核心: 修改操作→更新MainService→刷新Adapter)
*/
private void bindEditModeTask ( final TaskContentViewHolder holder , final PositionTaskModel task , final int position ) {
// 4.1 绑定基础数据(描述+距离条件)
String taskDesc = task . getTaskDescription ( ) = = null ? " 未设置描述 " : task . getTaskDescription ( ) ;
holder . tvTaskDesc . s etText ( String . format ( " 任务:%s " , taskDesc ) ) ;
String distanceCond = task . isGreaterThan ( ) ? " 大于 " : " 小于 " ;
holder . tvTaskDistance . setText ( String . format ( " 条件:%s %d 米 " , distanceCond , task . getDiscussDistance ( ) ) ) ;
holder . tvStartTim e . setText ( genSelectedTimeText ( task . getStartTim e( ) ) ) ;
LogUtils . d ( TAG , " bindEditModeTask position= " + position + " taskId= " + task . getTaskId ( ) ) ;
String desc = task . g etTaskDescription ( ) = = null ? " 未设置描述 " : task . getTaskDescription ( ) ;
holder . tvTaskDesc . setText ( String . format ( " 任务:%s " , desc ) ) ;
String cond = task . isGreaterThan ( ) ? " 大于 " : " 小于 " ;
holder . tvTaskDistanc e . setText ( String . format ( " 条件:%s %d 米 " , cond , task . getDiscussDistanc e( ) ) ) ;
holder . tvStartTime . setText ( genSelectedTimeText ( task . getStartTime ( ) ) ) ;
// 4.2 绑定“启用开关”(修复:先解绑监听→设值→再绑定监听,避免设值触发回调)
holder . cbTaskEnable . setOnCheckedChangeListener ( null ) ;
holder . cbTaskEnable . setChecked ( task . isEnable ( ) ) ;
holder . cbTaskEnable . setEnabled ( mCurrentViewMode = = VIEW_MODE_EDIT ) ; // 编辑模式才允许操作
holder . cbTaskEnable . setEnabled ( mCurrentViewMode = = VIEW_MODE_EDIT ) ;
// 4.3 编辑模式特有:显示编辑/删除按钮(仅编辑模式可见)
holder . btnEditTask . setVisibility ( View . VISIBLE ) ;
holder . btnDeleteTask . setVisibility ( View . VISIBLE ) ;
// 4.4 删除按钮逻辑( 核心: 删除→同步MainService→刷新Adapter)
holder . btnDeleteTask . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
if ( mMainService = = null ) {
showToast ( " 删除失败:服务未就绪 " ) ;
LogUtils . e ( TAG , " 删除任务失败: MainService实例为空 " ) ;
return ;
}
YesNoAlertDialog . show ( getContext ( ) , " 删除任务提示 " , " 是否删除此项位置任务? " , new YesNoAlertDialog . OnDialogResultListener ( ) {
@Override
public void onNo ( ) {
}
try {
// 步骤1: 调用MainService删除任务( 服务是唯一数据源, 确保数据一致性)
mMainService . deleteTask ( task . getTaskId ( ) ) ; // 需在MainService中实现deleteTask()方法(删除服务内全量任务列表中的对应项)
LogUtils . d ( TAG , " 调用MainService删除任务: ID= " + task . getTaskId ( ) + " ( 位置ID=" + mBindPositionId + " ) " ) ;
@Override
public void onYes ( ) {
LogUtils . d ( TAG , " 删除按钮点击 position= " + position + " taskId= " + task . getTaskId ( ) ) ;
if ( mMainService = = null ) {
showToast ( " 删除失败:服务未就绪 " ) ;
LogUtils . e ( TAG , " 删除失败: MainService为空 " ) ;
return ;
}
try {
mMainService . deleteTask ( task . getTaskId ( ) ) ;
LogUtils . d ( TAG , " 服务删除任务成功 taskId= " + task . getTaskId ( ) ) ;
notifyItemRemoved ( position ) ;
notifyItemRangeChanged ( position , mAdapterData . size ( ) ) ;
// 步骤2: 从Adapter数据源移除任务( 避免等待同步, 立即反馈UI)
//mAdapterData.remove(position) ;
// 步骤3: 刷新Adapter( 局部刷新+范围通知,避免列表错乱)
notifyItemRemoved ( position ) ;
notifyItemRangeChanged ( position , mAdapterData . size ( ) ) ;
if ( mOnTaskUpdatedListener ! = null & & mBindPositionId ! = null ) {
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , new ArrayList < > ( mAdapterData ) ) ;
}
showToast ( " 任务已删除 " ) ;
LogUtils . d ( TAG , " Adapter已移除任务, 刷新列表( 位置索引= " + position + " ) " ) ;
} catch ( Exception e ) {
LogUtils . e ( TAG , " 删除异常: " + e . getMessage ( ) , e ) ;
showToast ( " 删除失败,请重试 " ) ;
syncTasksFromMainService ( ) ;
}
}
// 步骤4: 通知外部( 如Activity) 任务已更新
if ( mOnTaskUpdatedListener ! = null & & mBindPositionId ! = null ) {
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , new ArrayList < PositionTaskModel > ( mAdapterData ) ) ;
}
showToast ( " 任务已删除(已同步至服务) " ) ;
} catch ( Exception e ) {
LogUtils . d ( TAG , " 删除任务失败(服务调用/Adapter刷新异常) : " + e . getMessage ( ) ) ;
showToast ( " 删除失败,请重试 " ) ;
// 异常时重新同步数据( 确保Adapter与服务一致)
syncTasksFromMainService ( ) ;
}
} ) ;
}
} ) ;
// 4.5 编辑按钮逻辑( 核心: 修改后同步MainService→刷新Adapter)
holder . btnEditTask . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
LogUtils . d ( TAG , " 编辑按钮点击 position= " + position + " taskId= " + task . getTaskId ( ) ) ;
if ( mMainService = = null ) {
showToast ( " 编辑失败:服务未就绪 " ) ;
LogUtils . e ( TAG , " 编辑任务 失败: MainService实例 为空 " ) ;
LogUtils . e ( TAG , " 编辑失败: MainService为空 " ) ;
return ;
}
// 弹出编辑弹窗(修改后同步服务)
showEditTaskDialog ( task , position ) ;
}
} ) ;
// 4.6 启用开关逻辑( 核心: 状态变更→同步MainService→刷新Adapter)
holder . cbTaskEnable . setOnCheckedChangeListener ( new CompoundButton . OnCheckedChangeListener ( ) {
@Override
public void onCheckedChanged ( CompoundButton buttonView , final boolean isChecked ) {
LogUtils . d ( TAG , " 开关状态变更 taskId= " + task . getTaskId ( ) + " isChecked= " + isChecked ) ;
if ( mMainService = = null ) {
showToast ( " 状态修改失败:服务未就绪 " ) ;
LogUtils . e ( TAG , " 修改任务启用状态失败: MainService实例为空 " ) ;
// 回滚开关状态( 避免UI与服务不一致)
buttonView . setChecked ( ! isChecked ) ;
return ;
}
try {
// 步骤1: 更新任务状态( 先改内存数据, 确保UI反馈及时)
task . setIsEnable ( isChecked ) ;
LogUtils . d ( TAG , " 更新任务启用状态: ID= " + task . getTaskId ( ) + " ,新状态= " + ( isChecked ? " 启用 " : " 禁用 " ) ) ;
// 步骤2: 调用MainService同步状态( 服务是唯一数据源, 持久化变更)
mMainService . updateTaskStatus ( task ) ; // 需在MainService中实现updateTaskStatus()方法( 更新服务内任务的isEnable字段)
LogUtils . d ( TAG , " 调用MainService同步任务状态( 已 " + ( isChecked ? " 启用 " : " 禁用 " ) + " ) " ) ;
// 步骤3: 延迟刷新Adapter( 避免列表滚动/布局计算时异常)
mMainService . updateTaskStatus ( task ) ;
mRvTasks . post ( new Runnable ( ) {
@Override
public void run ( ) {
notifyItemChanged ( position ) ;
// 通知外部任务已更新
if ( mOnTaskUpdatedListener ! = null & & mBindPositionId ! = null ) {
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , new ArrayList < PositionTaskModel > ( mAdapterData ) ) ;
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , new ArrayList < > ( mAdapterData ) ) ;
}
}
} ) ;
} catch ( Exception e ) {
LogUtils . d ( TAG , " 修改任务启用状态失败: " + e . getMessage ( ) ) ;
showToast ( " 状态修改失败,请重试 " ) ;
// 回滚状态( UI与服务保持一致)
LogUtils . e ( TAG , " 开关变更异常: " + e . getMessage ( ) , e );
buttonView . setChecked ( ! isChecked ) ;
task . setIsEnable ( ! isChecked ) ;
// 重新同步数据(修复可能的不一致)
syncTasksFromMainService ( ) ;
}
}
} ) ;
}
private String genSelectedTimeText ( long timeMillis ) {
// 2. 格式化时间字符串( Java 7 用 SimpleDateFormat, 需处理 ParseException)
SimpleDateFormat sdf = new SimpleDateFormat ( " yyyy-MM-dd HH:mm " , Locale . getDefault ( ) ) ;
String formattedDateTime = sdf . format ( new Date ( timeMillis ) ) ; // Date 需导入 java.util.Date
return formattedDateTime ;
}
/**
* 编辑任务弹窗( 核心: 保存修改→同步MainService→刷新Adapter)
*/
private void showEditTaskDialog ( final PositionTaskModel task , final int position ) {
LogUtils . d ( TAG , " showEditTaskDialog position= " + position + " taskId= " + task . getTaskId ( ) ) ;
final Context context = getContext ( ) ;
if ( context = = null ) {
LogUtils . w ( TAG , " 编辑弹窗无法显示: 上下文为空" ) ;
LogUtils . w ( TAG , " showEditTaskDialog 上下文为空" ) ;
return ;
}
// 加载弹窗布局
View dialogView = LayoutInflater . from ( context ) . inflate ( R . layout . dialog_edit_task , null ) ;
final EditText etEditDesc = dialogView . findViewById ( R . id . et_edit_task_desc ) ;
final RadioGroup rgDistanceCondition = dialogView . findViewById ( R . id . rg_distance_condition ) ;
final EditText etEditDistance = dialogView . findViewById ( R . id . et_edit_distance ) ;
Button btnCancel = dialogView . findViewById ( R . id . btn_dialog_cancel ) ;
Button btnCancel = dialogView . findViewById ( R . id . btn_dialog_cancel ) ;
Button btnSave = dialogView . findViewById ( R . id . btn_dialog_save ) ;
final Button btnSelectTime = dialogView . findViewById ( R . id . btn_select_time ) ;
final TextView tvSelectedTime = dialogView . findViewById ( R . id . tv_selected_time ) ;
tvSelectedTime . setText ( genSelectedTimeText ( task . getStartTime ( ) ) ) ;
// 绑定外层对话框内的控件
final Button btnSelectTime = ( Button ) dialogView . findViewById ( R . id . btn_select_time ) ;
final TextView tv_SelectedTime = ( TextView ) dialogView . findViewById ( R . id . tv_selected_time ) ;
Calendar initCal = Calendar . getInstance ( ) ;
initCal . setTimeInMillis ( task . getStartTime ( ) ) ;
int y = initCal . get ( Calendar . YEAR ) ;
int M = initCal . get ( Calendar . MONTH ) + 1 ;
int d = initCal . get ( Calendar . DAY_OF_MONTH ) ;
int h = initCal . get ( Calendar . HOUR_OF_DAY ) ;
int m = initCal . get ( Calendar . MINUTE ) ;
tv_SelectedTime . setText ( genSelec ted TimeText ( task . getStartTime ( ) ) ) ;
// 核心:从 long 时间戳解析年月日时分,用于初始化弹窗
// --------------------------
Calendar initCalendar = Calendar . getInstance ( ) ;
initCalendar . setTimeInMillis ( task . getStartTime ( ) ) ; // 将 long 时间戳传入 Calendar
// 从 Calendar 中解析出年月日时分(对应弹窗需要的参数格式)
int initYear = initCalendar . get ( Calendar . YEAR ) ;
int initMonth = initCalendar . get ( Calendar . MONTH ) + 1 ; // 关键: Calendar 月份0-11, 转成1-12
int initDay = initCalendar . get ( Calendar . DAY_OF_MONTH ) ;
int initHour = initCalendar . get ( Calendar . HOUR_OF_DAY ) ; // 24小时制
int initMinute = initCalendar . get ( Calendar . MINUTE ) ;
// 初始化弹窗,用解析出的年月日时分设置默认选中时间
final DateTimePickerPopup dateTimePopup = new DateTimePickerPopup . Builder ( context )
final DateTimePickerPopup dateTimePopup = new Da teTimePickerPopup . Builder ( context )
. setDateTimeRange ( 2020 , 2030 , 1 , 12 , 1 , 31 , 0 , 23 , 0 , 59 )
// 用 long 时间戳解析出的参数设置初始时间
. setDefaultDateTime ( initYear , initMonth , initDay , initHour , initMinute )
. setDefaultDateTime ( y , M , d , h , m )
. setOnDateTimeSelectedListener ( new DateTimePickerPopup . OnDateTimeSelectedListener ( ) {
@Override
public void onDateTimeSelected ( int year , int month , int day , int hour , int minute ) {
// 处理选择的日期时间
// 1. 创建 Calendar 实例(用于组装日期时间)
Calendar calendar = Calendar . getInstance ( ) ;
// 2. 设置 Calendar 的年、月、日、时、分( 注意: Calendar 月份从 0 开始,需减 1)
calendar . set ( Calendar . YEAR , year ) ;
calendar . set ( Calendar . MONTH , month - 1 ) ; // 关键:传入的 month 是 1-12, 需转为 0-11
calendar . set ( Calendar . DAY_OF_MONTH , day ) ;
calendar . set ( Calendar . HOUR_OF_DAY , hour ) ; // 24小时制, 对应参数中的 hour( 0-23)
calendar . set ( Calendar . MINUTE , minute ) ;
calendar . set ( Calendar . SECOND , 0 ) ; // 秒默认设为 0, 避免随机值
calendar . set ( Calendar . MILLISECOND , 0 ) ; // 毫秒默认设为 0, 确保时间戳精确
// 3. 转为 long 类型时间戳(单位:毫秒,从 1970-01-01 00:00:00 开始计算)
long timeMillis = calendar . getTimeInMillis ( ) ;
// 4. 后续使用(示例:打印时间戳或传递给其他逻辑)
tv_SelectedTime . setText ( genSelectedTimeText ( timeMillis ) ) ;
task . setStartTime ( timeMillis ) ;
Calendar cal = Calendar . getInstance ( ) ;
cal . set ( year , month - 1 , day , hour , minute , 0 ) ;
cal . set ( Calendar . MILLISECOND , 0 ) ;
long time = cal . getTimeInMillis ( ) ;
tvSelectedTime . setText ( genSelectedTimeText ( time ) ) ;
task . setStartTime ( time ) ;
}
@Override
public void onCancel ( ) {
// 处理取消操作
}
public void onCancel ( ) { }
} )
. build ( ) ;
// 3. “选择时间”按钮点击事件(弹出 TimePickerPopup)
btnSelectTime . setOnClickListener ( new View . OnClickListener ( ) {
btnSelectTime . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( final View v ) {
public void onClick ( View v ) {
dateTimePopup . showAsDropDown ( btnSelectTime ) ;
}
} ) ;
// 初始化弹窗数据(填充当前任务信息)
etEditDesc . setText ( task . getTaskDescription ( ) = = null ? " " : task . getTaskDescription ( ) ) ;
etEditDesc . setSelection ( etEditDesc . getText ( ) . length ( ) ) ; // 光标定位到末尾
// 初始化距离条件(大于/小于)
etEditDesc . setSelection ( etEditDesc . getText ( ) . length ( ) ) ;
if ( task . isGreaterThan ( ) ) {
rgDistanceCondition . check ( R . id . rb_greater_than ) ;
} else {
rgDistanceCondition . check ( R . id . rb_less_than ) ;
}
etEditDistance . setText ( String . valueOf ( task . getDiscussDistance ( ) ) ) ; // 填充当前距离
etEditDistance . setText ( String . valueOf ( task . getDiscussDistance ( ) ) ) ;
// 创建并显示弹窗
final android . app . AlertDialog dialog = new android . app . AlertDialog . Builder ( context )
. setView ( dialogView )
. setCancelable ( false ) // 不允许点击外部关闭(避免未保存退出)
. setCancelable ( false )
. create ( ) ;
dialog . show ( ) ;
final OnDateSetListener listener = new OnDateSetListener ( ) {
@Override
public void onDateSet ( TimePickerDialog timePickerDialog , long p ) { }
} ;
final OnDateSetListener onSateSetListener = new OnDateSetListener ( ) {
@Override
public void onDateSet ( TimePickerDialog timePickerDialog , long p ) {
}
} ;
// 取消按钮:关闭弹窗(不做操作)
btnCancel . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
@@ -585,24 +515,22 @@ public class PositionTaskListView extends LinearLayout {
}
} ) ;
// 保存按钮: 校验输入→更新任务→同步服务→刷新UI
btnSave . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
// 1. 输入校验(避免无效数据)
String newDesc = etEditDesc . getText ( ) . toString ( ) . trim ( ) ;
String distance Str = etEditDistance . getText ( ) . toString ( ) . trim ( ) ;
String distStr = etEditDistance . getText ( ) . toString ( ) . trim ( ) ;
if ( distance Str . isEmpty ( ) ) {
showToast ( " 请输入有效距离( 1米及以上) " ) ;
if ( distStr . isEmpty ( ) ) {
showToast ( " 请输入有效距离 " ) ;
etEditDistance . requestFocus ( ) ;
return ;
}
int newDistance ;
int newDist ;
try {
newDistance = Integer . parseInt ( distance Str ) ;
if ( newDistance < 1 ) {
newDist = Integer . parseInt ( distStr ) ;
if ( newDist < 1 ) {
showToast ( " 距离不能小于1米 " ) ;
etEditDistance . requestFocus ( ) ;
return ;
@@ -613,144 +541,84 @@ public class PositionTaskListView extends LinearLayout {
return ;
}
// 2. 收集新数据(更新任务对象)
task . setTaskDescription ( newDesc ) ; // 新描述
task . setDiscussDistance ( newDistance ) ; // 新距离
task . setTaskDescription ( newDesc ) ;
task . setDiscussDistance ( newDist ) ;
boolean isGreater = rgDistanceCondition . getCheckedRadioButtonId ( ) = = R . id . rb_greater_than ;
task . setIsGreaterThan ( isGreater ) ; // 新距离条件(大于/小于)
task . setPositionId ( mBindPositionId ) ; // 确保位置ID不变( 防止错位)
task . setIsGreaterThan ( isGreater ) ;
task . setPositionId ( mBindPositionId ) ;
try {
// 3. 调用 MainService同步修改(服务是唯一数据源,持久化变更)
mMainService . updateTask ( task ) ; // 需在MainService中实现updateTask()方法(更新服务内任务的字段)
LogUtils . d ( TAG , " 调用MainService更新任务: ID= " + task . getTaskId ( ) + " (描述= " + newDesc + " ,距离= " + newDistance + " 米) " ) ;
// 4. 更新Adapter数据源( 立即反馈UI)
m MainService. updateTask ( task ) ;
LogUtils . d ( TAG , " 保存修改成功 taskId= " + task . getTaskId ( ) ) ;
mAdapterData . set ( position , task ) ;
// 5. 延迟刷新Adapter( 避免弹窗未关闭时布局异常)
mRvTasks . post ( new Runnable ( ) {
@Override
public void run ( ) {
notifyItemChanged ( position ) ;
// 通知外部任务已更新
if ( mOnTaskUpdatedListener ! = null & & mBindPositionId ! = null ) {
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , new ArrayList < PositionTaskModel > ( mAdapterData ) ) ;
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , new ArrayList < > ( mAdapterData ) ) ;
}
}
} ) ;
dialog . dismiss ( ) ;
showToast ( " 任务已更新(已同步至服务) " ) ;
showToast ( " 任务已更新 " ) ;
} catch ( Exception e ) {
LogUtils . d ( TAG , " 保存任务修改失败: " + e . getMessage ( ) ) ;
LogUtils . e ( TAG , " 保存异常: " + e . getMessage ( ) , e );
showToast ( " 保存失败,请重试 " ) ;
// 重新同步数据(修复可能的不一致)
syncTasksFromMainService ( ) ;
}
}
} ) ;
}
// ---------------------- ViewHolder 定义(完全适配布局,无修改) ----------------------
// 基础抽象ViewHolder( 统一父类, 适配多视图类型)
// ---------------------- ViewHolder ----------------------
public abstract class TaskViewHolder extends RecyclerView . ViewHolder {
public TaskViewHolder ( @NonNull View itemView ) {
super ( itemView ) ;
}
}
// 空提示ViewHolder( 对应 item_task_empty.xml)
public class EmptyViewHolder extends TaskViewHolder {
public EmptyViewHolder ( @NonNull View itemView ) {
super ( itemView ) ;
}
}
// 简单模式ViewHolder( 对应 item_position_task_simple.xml, 带isBingo红点)
public class SimpleTaskViewHolder extends TaskViewHolder {
TextView tvSimpleTaskDesc ; // 任务描述
TextView tvSimpleDistanceCond ; // 距离条件(大于/小于+距离)
TextView tvStartTime ;
TextView tvSimpleIsEnable ; // 启用状态(已启用/已禁用)
View vBingoDot ; // isBingo红点( 任务触发时显示)
TextView tvSimpleTaskDesc ;
TextView tvSimpleDistanceCond ;
TextView tvStartTime ;
TextView tvSimpleIsEnable ;
View vBingoDot ;
public SimpleTaskViewHolder ( @NonNull View itemView ) {
super ( itemView ) ;
// 绑定简单模式布局控件( 与XML控件ID严格对应)
tvSimpleTaskDesc = itemView . findViewById ( R . id . tv_simple_task_desc ) ;
tvSimpleDistanceCond = itemView . findViewById ( R . id . tv_simple_distance_cond ) ;
tvStartTime = itemView . findViewById ( R . id . tv_starttime ) ;
tvStartTime = itemView . findViewById ( R . id . tv_starttime ) ;
tvSimpleIsEnable = itemView . findViewById ( R . id . tv_simple_is_enable ) ;
vBingoDot = itemView . findViewById ( R . id . v_bingo_dot ) ;
}
}
// 编辑模式ViewHolder( 对应 item_task_content.xml, 带编辑/删除/开关)
public class TaskContentViewHolder extends TaskViewHolder {
TextView tvTaskDesc ; // 任务描述
TextView tvTaskDistance ; // 距离条件
TextView tvStartTime ;
CompoundButton cbTaskEnable ; // 启用开关
Button btnEditTask ; // 编辑按钮
Button btnDeleteTask ; // 删除按钮
TextView tvTaskDesc ;
TextView tvTaskDistance ;
TextView tvStartTime ;
CompoundButton cbTaskEnable ;
Button btnEditTask ;
Button btnDeleteTask ;
public TaskContentViewHolder ( @NonNull View itemView ) {
super ( itemView ) ;
// 绑定编辑模式布局控件( 与XML控件ID严格对应)
tvTaskDesc = itemView . findViewById ( R . id . tv_task_desc ) ;
tvTaskDistance = itemView . findViewById ( R . id . tv_task_distance ) ;
tvStartTime = itemView . findViewById ( R . id . tv_starttime ) ;
tvStartTime = itemView . findViewById ( R . id . tv_starttime ) ;
cbTaskEnable = itemView . findViewById ( R . id . cb_task_enable ) ;
btnEditTask = itemView . findViewById ( R . id . btn_edit_task ) ;
btnDeleteTask = itemView . findViewById ( R . id . btn_delete_task ) ;
}
}
}
// ---------------------- 新增: 外部调用“新增任务”方法( 适配MainService) ----------------------
/**
* 新增任务( 对外提供, 如Activity调用添加任务)
* @param newTask 待新增的任务( 需关联当前位置ID)
*/
public void addNewTask ( PositionTaskModel newTask ) {
if ( mMainService = = null ) {
showToast ( " 新增任务失败:服务未就绪 " ) ;
LogUtils . e ( TAG , " 新增任务失败: MainService实例为空 " ) ;
return ;
}
if ( newTask = = null ) {
showToast ( " 新增任务失败:任务数据为空 " ) ;
LogUtils . e ( TAG , " 新增任务失败:待新增任务对象为空 " ) ;
return ;
}
if ( mBindPositionId = = null | | mBindPositionId . trim ( ) . isEmpty ( ) ) {
showToast ( " 新增任务失败:未关联位置 " ) ;
LogUtils . e ( TAG , " 新增任务失败: 未绑定位置ID( 需先调用init()方法) " ) ;
return ;
}
try {
// 1. 关联任务到当前位置(确保任务属于当前位置)
newTask . setPositionId ( mBindPositionId ) ;
// 2. 调用MainService新增任务( 服务是唯一数据源, 持久化数据)
mMainService . addTask ( newTask ) ; // 需在MainService中实现addTask()方法(添加到服务内全量任务列表)
LogUtils . d ( TAG , " 调用MainService新增任务: ID= " + newTask . getTaskId ( ) + " ( 位置ID=" + mBindPositionId + " ) " ) ;
// 3. 重新同步数据(从服务拉取最新列表,避免本地计算错误)
syncTasksFromMainService ( ) ;
// 4. 通知外部任务已更新
if ( mOnTaskUpdatedListener ! = null ) {
mOnTaskUpdatedListener . onTaskUpdated ( mBindPositionId , getCurrentPosTasks ( ) ) ;
}
showToast ( " 新增任务成功(已同步至服务) " ) ;
} catch ( Exception e ) {
LogUtils . d ( TAG , " 新增任务失败: " + e . getMessage ( ) ) ;
showToast ( " 新增失败,请重试 " ) ;
// 重新同步数据(修复可能的不一致)
syncTasksFromMainService ( ) ;
}
}
}