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]就会触发数组越界错误。
修复方法
可以通过两种方式修正:
- 在判断分支中添加
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]; }
- 使用
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
相关产品推荐
相关产品推荐

