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

Xamarin Android集成MySQL时ListView触发数组越界异常问题

问题分析与解决方案

异常根源

你遇到的System.IndexOutOfRangeException大概率来自以下两个核心问题:

  1. 使用索引访问DataReader列的不确定性:rdr[1]依赖查询返回列的顺序,一旦表结构调整(比如列顺序变更)或查询返回的列与预期不符,就会触发索引越界。
  2. 非强类型集合与资源管理问题: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:

  1. 创建自定义列表项布局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>
  1. 创建实体类对应表字段:
public class BoughtItemHistory
{
    public string ItemName { get; set; }
    public decimal ItemPrice { get; set; }
    // 其他字段按需添加
}
  1. 自定义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;
    }
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:15:31