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

Garmin Connect IQ使用ViewLoop时发生无堆栈数组越界错误

排查Garmin ViewLoop应用的数组越界错误

开发Garmin手表应用时使用ViewLoop组件,出现Array Out Of Bounds Error。应用从对象数组生成视图并添加至ViewLoop,已添加调试打印语句,相关代码及运行输出如下:

应用主类代码

import Toybox.Application;
import Toybox.Lang;
import Toybox.WatchUi;

class AareGuruGarminApp extends Application.AppBase {
    var objects;

    function initialize() {
        AppBase.initialize();
        objects = [
            new Object("Object 1", "Value 1"),
            new Object("Object 2", "Value 2"),
            new Object("Object 3", "Value 3")
        ];
    }

    function onStart(state as Dictionary?) as Void {
    }

    function onStop(state as Dictionary?) as Void {
    }

    function getInitialView() as [Views] or [Views, InputDelegates] {
        System.println("Trying to generate ViewLoop");
        var viewLoop = new WatchUi.ViewLoop(new AareGuruGarminViewLoopFactory(objects), {});
        System.println("Successfully generated ViewLoop");
        System.println("Returning ViewLoop");
        return [viewLoop];
    }

}

function getApp() as AareGuruGarminApp {
    return Application.getApp() as AareGuruGarminApp;
}

class Object {
    var title;
    var description;

    function initialize(newObjectTitle as String, newObjectDescription as String) {
        title = newObjectTitle;
        description = newObjectDescription;
    }
}

视图类代码

import Toybox.Graphics;
import Toybox.WatchUi;

class AareGuruGarminView extends WatchUi.View {
    var object;

    function initialize(objectToDisplay as Object) {
        System.println("Initializing view for " + objectToDisplay.title);

        View.initialize();
        object = objectToDisplay;

        System.println("Initialized view for " + object.title);
    }

    function onLayout(dc as Dc) as Void {
        System.println("'onLayout' called");
        dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_TRANSPARENT);
        dc.drawText(
            dc.getWidth() / 2,                      
            dc.getHeight() / 2,                     
            Graphics.FONT_LARGE,                    
            object.title,                          
            Graphics.TEXT_JUSTIFY_CENTER            
        );
        dc.drawText(
            dc.getWidth() / 2,                      
            dc.getHeight() / 4,                     
            Graphics.FONT_LARGE,                    
            object.description,                          
            Graphics.TEXT_JUSTIFY_CENTER            
        );
    }

    function onShow() as Void {
        System.println("'onShow' called");
    }

    function onUpdate(dc as Dc) as Void {
        System.println("'onUpdate' called");
        View.onUpdate(dc);
    }

    function onHide() as Void {
        System.println("'onHide' called");
    }
}

ViewLoop工厂类代码

import Toybox.WatchUi;

class AareGuruGarminViewLoopFactory extends WatchUi.ViewLoopFactory {
    var objectsForViews;
    function initialize(objects as [Object]) {
        objectsForViews = objects;
        System.println("Initialized ViewLoopFactory with " + objectsForViews.size() + " objects");
    }

    function getView(i) {
        System.println("Generating view for index " + i);
        var view;
        if (i >= objectsForViews.size()) {
            view = new AareGuruGarminView(new Object("empty", "empty"));
        }
        view = new AareGuruGarminView(objectsForViews[i]);

        System.println("Generated view for index " + i);

        return [view];
    }


    function getSize() {
        System.println("'getSize' called");
        System.println("Size is " + objectsForViews.size());
        return objectsForViews.size();
    }
}

运行调试输出

Trying to generate ViewLoop
Initialized ViewLoopFactory with 3 objects
'getSize' called
Size is 3
Successfully generated ViewLoop
Returning ViewLoop
Generating view for index 0
Initializing view for Object 1
Initialized view for Object 1
Generated view for index 0
Error: Array Out Of Bounds Error
Details: Failed to start CIQ Application
Stack:
Encountered app crash.

问题原因及修复方案

问题根源

错误出在AareGuruGarminViewLoopFactory的getView方法中:

  • 虽然写了i >= objectsForViews.size()的判断分支,但该分支执行后没有终止方法,后续代码view = new AareGuruGarminView(objectsForViews[i]);会直接覆盖之前的赋值。
  • 当i超出数组长度时,直接访问objectsForViews[i]就会触发数组越界错误。

修复方法

可以通过两种方式修正:

  1. 在判断分支中添加return语句,避免执行后续代码:
function getView(i) {
    System.println("Generating view for index " + i);
    var view;
    if (i >= objectsForViews.size()) {
        view = new AareGuruGarminView(new Object("empty", "empty"));
        return [view]; // 添加return终止方法
    }
    view = new AareGuruGarminView(objectsForViews[i]);

    System.println("Generated view for index " + i);

    return [view];
}
  1. 使用else分支包裹正常逻辑,确保只有在索引合法时才访问数组:
function getView(i) {
    System.println("Generating view for index " + i);
    var view;
    if (i >= objectsForViews.size()) {
        view = new AareGuruGarminView(new Object("empty", "empty"));
    } else {
        view = new AareGuruGarminView(objectsForViews[i]);
    }

    System.println("Generated view for index " + i);

    return [view];
}

修正后,当索引超出数组范围时会使用默认视图,而不会触发数组越界错误。

内容的提问来源于stack exchange,提问作者Mattia Gisiger

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:55:57