Xamarin Android集成MySQL时ListView触发数组越界异常问题
问题分析与解决方案
异常根源
你遇到的System.IndexOutOfRangeException大概率来自以下两个核心问题:
- 使用索引访问DataReader列的不确定性:
rdr[1]依赖查询返回列的顺序,一旦表结构调整(比如列顺序变更)或查询返回的列与预期不符,就会触发索引越界。 - 非强类型集合与资源管理问题:
ArrayList属于弱类型集合,搭配ArrayAdapter时可能存在隐式类型转换问题;同时数据库连接、DataReader未正确释放,可能引发隐性异常。
分步修复方案
1. 修正查询语句,避免select *
将select *改为明确指定需要的列,确保返回列的确定性:
// Constants.cs 修改查询语句 public static string selectAllQueryHistory = "select itemName from boughtitemhistory order by id desc";
2. 替换弱类型集合为强类型
用List<string>替代ArrayList,适配ArrayAdapter的泛型版本,避免类型转换异常:
// MainActivity.cs 替换字段定义 private List<string> data = new List<string>();
3. 重构数据库操作逻辑,规范资源管理
使用using语句自动释放数据库资源,同时改用列名访问DataReader,避免索引依赖:
// MainActivity.cs 重构LoadData方法 private async void LoadData() { var itemNames = new List<string>(); try { // using语句自动释放连接 using (var conn = new MySqlConnection(Constants.connectionString)) { await conn.OpenAsync(); // using语句自动释放命令对象 using (var cmd = new MySqlCommand(Constants.selectAllQueryHistory, conn)) { // using语句自动释放DataReader using (var rdr = await cmd.ExecuteReaderAsync()) { while (await rdr.ReadAsync()) { // 用列名访问,同时检查空值 var ordinal = rdr.GetOrdinal("itemName"); if (!rdr.IsDBNull(ordinal)) { itemNames.Add(rdr.GetString(ordinal)); } else { itemNames.Add("(无数据)"); } } } } } // 确保在UI线程更新ListView RunOnUiThread(() => { listView1.Adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, itemNames); }); } catch (Exception ex) { // 捕获异常并提示,方便调试 RunOnUiThread(() => { Toast.MakeText(this, $"加载失败: {ex.Message}", ToastLength.Long).Show(); }); } }
4. 扩展:多列数据展示(如果需要)
如果要展示表中多个字段(如itemName、itemPrice等),需要自定义Adapter:
- 创建自定义列表项布局
list_item_history.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/tv_item_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" android:textStyle="bold"/> <TextView android:id="@+id/tv_item_price" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:textColor="#666"/> </LinearLayout>
- 创建实体类对应表字段:
public class BoughtItemHistory { public string ItemName { get; set; } public decimal ItemPrice { get; set; } // 其他字段按需添加 }
- 自定义Adapter:
public class HistoryAdapter : BaseAdapter<BoughtItemHistory> { private List<BoughtItemHistory> _items; private Context _context; public HistoryAdapter(Context context, List<BoughtItemHistory> items) { _context = context; _items = items; } public override BoughtItemHistory this[int position] => _items[position]; public override int Count => _items.Count; public override long GetItemId(int position) => position; public override View GetView(int position, View convertView, ViewGroup parent) { View view = convertView ?? LayoutInflater.From(_context).Inflate(Resource.Layout.list_item_history, parent, false); var item = _items[position]; view.FindViewById<TextView>(Resource.Id.tv_item_name).Text = item.ItemName; view.FindViewById<TextView>(Resource.Id.tv_item_price).Text = $"价格: {item.ItemPrice:C}"; return view; } }
- 修改LoadData方法填充实体类并绑定Adapter:
private async void LoadData() { var historyList = new List<BoughtItemHistory>(); try { using (var conn = new MySqlConnection(Constants.connectionString)) { await conn.OpenAsync(); using (var cmd = new MySqlCommand("select itemName, itemPrice from boughtitemhistory order by id desc", conn)) { using (var rdr = await cmd.ExecuteReaderAsync()) { while (await rdr.ReadAsync()) { historyList.Add(new BoughtItemHistory { ItemName = rdr.IsDBNull(rdr.GetOrdinal("itemName")) ? "" : rdr.GetString("itemName"), ItemPrice = rdr.IsDBNull(rdr.GetOrdinal("itemPrice")) ? 0 : rdr.GetDecimal("itemPrice") }); } } } } RunOnUiThread(() => { listView1.Adapter = new HistoryAdapter(this, historyList); }); } catch (Exception ex) { RunOnUiThread(() => { Toast.MakeText(this, $"加载失败: {ex.Message}", ToastLength.Long).Show(); }); } }
内容的提问来源于stack exchange,提问作者LegendEvent
相关产品推荐
相关产品推荐

