字符串列表转Menu结构遇索引无效报错及性能优化求助
搞定两个核心问题:索引越界报错 + 批量创建卡顿
嘿,我来帮你解决这两个头疼的问题——先搞定那个烦人的索引错误,再优化性能避免卡顿!
一、先解决「Invalid index 0, size is 0」的报错
你碰到这个错误的本质太直白了:你初始化的menus是个完全空的集合,连一个元素都没有,直接调用menus.get(restaurantCounter)肯定抓瞎啊!得先把menus的层级结构搭起来,再往里填数据。
修正后的基础逻辑(假设是单个餐厅的场景)
private List<List<Restaurant.Menu>> menus = new ArrayList<>(); // 先把数据库里的数据取出来,变量名统一规范下更清晰 ArrayList<String> menuNames = tinydb.getListString("MenuName"); ArrayList<String> foodNames = tinydb.getListString("FoodName"); ArrayList<String> foodPrices = tinydb.getListString("FoodPrice"); // 第一步:先给menus加第一层(餐厅维度),放一个空的菜单列表进去 menus.add(new ArrayList<>()); // 把这个刚加的菜单列表取出来,方便后续操作 List<Restaurant.Menu> currentRestaurantMenus = menus.get(0); // 第二步:遍历菜单名,逐个创建Menu对象塞进去 for (int j = 0; j < menuNames.size(); j++) { Restaurant.Menu menu = new Restaurant.Menu(); menu.name = menuNames.get(j); // 这里要注意!你得明确FoodName和FoodPrice怎么对应到每个Menu // 比如是每个菜单对应连续的一组食物?还是有别的映射规则? // (这部分得根据你的数据结构自己调整) currentRestaurantMenus.add(menu); }
如果是多餐厅的场景,你得先循环处理每个餐厅,给menus里每个餐厅都加一个空的菜单列表,再填充对应的数据。
二、优化批量创建对象的卡顿问题
你说逐个创建对象会卡10秒,大概率是因为集合频繁扩容或者在UI线程做了耗时操作,咱从这两点入手优化:
1. 给集合提前指定容量,避免频繁扩容
ArrayList默认初始容量是10,当元素超过容量时会自动扩容(每次扩到原来的1.5倍),扩容要做内存拷贝,次数多了就会卡。咱直接根据已知的列表大小指定初始容量:
// 初始化menus时直接指定餐厅数量(比如只有1个餐厅就写1) List<List<Restaurant.Menu>> menus = new ArrayList<>(1); // 初始化餐厅的菜单列表时,直接用menuNames的大小当容量 List<Restaurant.Menu> currentRestaurantMenus = new ArrayList<>(menuNames.size()); menus.add(currentRestaurantMenus); // 每个Menu里的foods集合也提前指定容量(比如你知道每个菜单有3个食物) for (int j = 0; j < menuNames.size(); j++) { Restaurant.Menu menu = new Restaurant.Menu(); menu.name = menuNames.get(j); // 提前给foods设好容量,不用它自己瞎扩容 menu.foods = new ArrayList<>(3); // 这里换成你实际的单菜单食物数量 currentRestaurantMenus.add(menu); }
2. 批量处理食物数据,减少零散操作
如果你的FoodName和FoodPrice是按菜单分组存的(比如菜单0对应前3个食物,菜单1对应接下来3个),那就批量把对应食物塞到菜单里,别零散操作:
// 示例:假设每个菜单固定对应3个食物 int foodsPerMenu = 3; for (int j = 0; j < menuNames.size(); j++) { Restaurant.Menu menu = new Restaurant.Menu(); menu.name = menuNames.get(j); menu.foods = new ArrayList<>(foodsPerMenu); // 批量把当前菜单的食物都加进去 int startIndex = j * foodsPerMenu; for (int k = 0; k < foodsPerMenu; k++) { int foodIndex = startIndex + k; if (foodIndex >= foodNames.size()) break; // 防止越界 Restaurant.Food food = new Restaurant.Food(); food.name = foodNames.get(foodIndex); food.price = foodPrices.get(foodIndex); menu.foods.add(food); } currentRestaurantMenus.add(menu); }
3. 别在UI线程做耗时操作!
如果这段代码是在UI线程跑的,大量对象创建和集合操作会直接卡UI。赶紧把数据解析逻辑放到后台线程(比如用Coroutines、AsyncTask或者线程池),解析完了再切回UI线程更新视图,这样用户就不会感觉到卡顿了。
最后提醒
一定要搞清楚MenuName、FoodName、FoodPrice三个列表的对应关系——是每个菜单对应连续的一组食物?还是有别的映射规则?这直接决定了你的循环逻辑对不对。
内容的提问来源于stack exchange,提问作者ozo
相关产品推荐
相关产品推荐

