Titanium应用ListView点击时获取数据错误问题排查
Titanium ListView 点击列表项参数传递错误修复方案
问题描述
我在Titanium应用中从数据库拉取数据,通过循环生成ListView的Section展示章节标题及对应练习内容。目前除了点击前7个Section的列表项时,都会跳转到最后一个Section的练习详情外,其余功能正常。确认是参数传递问题,但无法正确修复。
原Controller代码
var args = $.args; // Here we need to get the courseID and then return the correct sessions for that course var courseID = args.courseID; $.courseDetailWindow.title = args.courseTitle.text.toUpperCase(); // open the DB var db = Ti.Database.open('myDB'); // set the ListSections outside of the loop var sections = []; // do the loop of sessions for this course var sessionRS = db.execute('SELECT session_id, session_name, session_intro, session_course_id FROM sessions WHERE session_course_id = ' + courseID); while (sessionRS.isValidRow()) { var sessionName = sessionRS.fieldByName('session_name'); var sessionID = sessionRS.fieldByName('session_id'); // create the List Section var listSection = Ti.UI.createListSection({ headerTitle: sessionName}); // create the data set of drills var drillDataSet = []; // do the loop of drills for this session var drillRS = db.execute('SELECT drill_id, drill_name, drill_intro, drill_instructions, drill_video, drill_duration FROM drills WHERE session_id = ' + sessionID); while (drillRS.isValidRow()) { var drillName = drillRS.fieldByName('drill_name'); var drillDuration = drillRS.fieldByName('drill_duration'); var drillVideo = drillRS.fieldByName('drill_video'); var drillIntro = drillRS.fieldByName('drill_intro'); var drillInstructions = drillRS.fieldByName('drill_instructions'); // push the drill data into the array drillDataSet.push({ template : "drillTemplate", drillName : { text : drillName }, drillDuration : { text : "Drill - " + drillDuration }, drillInstructions : { text : drillInstructions }, drillIntro : { text : drillIntro }, drillIcon : { image : "images/control-cat-icon.png" }, drillVideo : { url : drillVideo} }); // assign those drills to the session listSection.setItems(drillDataSet); // move onto the next drill drillRS.next(); } // close the drill DB connection drillRS.close(); // add the session name and drills to the section sections.push(listSection); // move onto the next session sessionRS.next(); } // close the session DB connection sessionRS.close(); // Push all of the content to the main ListView $.courseDetailView.sections = sections; // Handle the List Row Tap function openDrillDetail(e) { var drillDetailWindow = Alloy.createController('/drillDetail', drillDataSet[e.itemIndex]).getView(); if (OS_IOS) { Alloy.Globals.tabGroup.activeTab.open(drillDetailWindow); } if (OS_ANDROID) { drillDetailWindow.open(); } }
原XML代码
<Alloy> <Window id="courseDetailWindow"> <ScrollView id="courseDetailScrollView"> <ListView id="courseDetailView" defaultItemTemplate="drillTemplate" onItemclick="openDrillDetail" height="Ti.UI.SIZE"> <Templates> <ItemTemplate name="drillTemplate" id="drillTemplate"> <View id="drillOuterView"> <View id="greenBlock"> <ImageView bindId="drillIcon" id="drillIcon" /> </View> <Label bindId="drillName" id="drillName" /> <Label bindId="drillDuration" id="drillDuration" /> </View> </ItemTemplate> </Templates> <!--<HeaderView id="sessionView"> <View height="Ti.UI.SIZE" layout="vertical"> <Label id="sessionTitle" text="Session 1"></Label> </View>> </HeaderView>--> <ListSection id="drillSection"> <ListItem template="drillTemplate" id="drillView"/> </ListSection> </ListView> </ScrollView> </Window> </Alloy>
问题分析
核心问题出在变量作用域与事件参数获取逻辑上:
drillDataSet是在Session循环内部声明的变量,每次循环都会覆盖该变量,循环结束后它仅保留最后一个Session的练习数据集。openDrillDetail函数中直接使用drillDataSet[e.itemIndex],导致无论点击哪个Section的项,都会从最后一个Session的数据集中取对应索引的项,最终跳转到错误的详情页。
修复方案
修复步骤
- 保存所有Session的练习数据集:声明全局数组
allDrillDataSets,在每个Session循环结束后,将当前的drillDataSet存入该数组,保留所有Session的练习数据。 - 通过点击事件索引定位正确数据:利用事件对象
e的sectionIndex(当前点击的Section索引)和itemIndex(当前Section内的项索引),从allDrillDataSets中取出对应的数据。 - 优化ListView项设置逻辑:将
listSection.setItems(drillDataSet)移到Drill循环结束后执行,避免重复设置Section项,提升性能。
修改后的Controller代码
var args = $.args; // 获取课程ID并设置窗口标题 var courseID = args.courseID; $.courseDetailWindow.title = args.courseTitle.text.toUpperCase(); // 打开数据库 var db = Ti.Database.open('myDB'); // 存储所有Section的数组 var sections = []; // 新增:存储所有Session对应的练习数据集 var allDrillDataSets = []; // 查询当前课程下的所有Session var sessionRS = db.execute('SELECT session_id, session_name, session_intro, session_course_id FROM sessions WHERE session_course_id = ' + courseID); while (sessionRS.isValidRow()) { var sessionName = sessionRS.fieldByName('session_name'); var sessionID = sessionRS.fieldByName('session_id'); // 创建当前Session对应的ListSection var listSection = Ti.UI.createListSection({ headerTitle: sessionName}); // 存储当前Session的练习数据 var drillDataSet = []; // 查询当前Session下的所有练习 var drillRS = db.execute('SELECT drill_id, drill_name, drill_intro, drill_instructions, drill_video, drill_duration FROM drills WHERE session_id = ' + sessionID); while (drillRS.isValidRow()) { var drillName = drillRS.fieldByName('drill_name'); var drillDuration = drillRS.fieldByName('drill_duration'); var drillVideo = drillRS.fieldByName('drill_video'); var drillIntro = drillRS.fieldByName('drill_intro'); var drillInstructions = drillRS.fieldByName('drill_instructions'); // 将练习数据加入当前Session的数据集 drillDataSet.push({ template : "drillTemplate", drillName : { text : drillName }, drillDuration : { text : "Drill - " + drillDuration }, drillInstructions : { text : drillInstructions }, drillIntro : { text : drillIntro }, drillIcon : { image : "images/control-cat-icon.png" }, drillVideo : { url : drillVideo} }); drillRS.next(); } drillRS.close(); // 优化:在drill循环结束后一次性设置Section的项 listSection.setItems(drillDataSet); // 将当前Session的数据集存入全局数组 allDrillDataSets.push(drillDataSet); // 将Section加入全局sections数组 sections.push(listSection); sessionRS.next(); } sessionRS.close(); // 将所有Section设置到ListView $.courseDetailView.sections = sections; // 处理列表项点击事件 function openDrillDetail(e) { // 通过sectionIndex和itemIndex获取正确的练习数据 var selectedDrill = allDrillDataSets[e.sectionIndex][e.itemIndex]; var drillDetailWindow = Alloy.createController('/drillDetail', selectedDrill).getView(); if (OS_IOS) { Alloy.Globals.tabGroup.activeTab.open(drillDetailWindow); } if (OS_ANDROID) { drillDetailWindow.open(); } }
关键改动说明
- 新增
allDrillDataSets数组,持久化存储每个Session的练习数据集。 - 调整
listSection.setItems(drillDataSet)的调用位置,减少不必要的UI更新。 - 重构
openDrillDetail的参数获取逻辑,通过事件对象的双索引定位正确数据,彻底解决参数传递错误问题。
内容的提问来源于stack exchange,提问作者Simon Hume
相关产品推荐
相关产品推荐

