You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的数据集中取对应索引的项,最终跳转到错误的详情页。

修复方案

修复步骤

  1. 保存所有Session的练习数据集:声明全局数组allDrillDataSets,在每个Session循环结束后,将当前的drillDataSet存入该数组,保留所有Session的练习数据。
  2. 通过点击事件索引定位正确数据:利用事件对象e的sectionIndex(当前点击的Section索引)和itemIndex(当前Section内的项索引),从allDrillDataSets中取出对应的数据。
  3. 优化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:00:47