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

Xamarin.Android中如何向BaseAdapter追加项实现ListView加载更多?

在Xamarin.Android中给BaseAdapter追加新项的最优方案

你之前每次滚动到底部就重建适配器的做法确实会影响性能——这会让ListView重新渲染所有现有项,还可能丢失滚动状态。正确的做法是复用同一个适配器实例,直接更新它的数据源,再通知数据变化。下面是具体实现步骤和代码示例:

第一步:改造你的自定义Adapter

首先,让你的AllContactsListAdapter持有一个可变的数据源列表,并提供一个公共方法来批量添加新数据,这样既保证封装性,又能安全地更新数据:

public class AllContactsListAdapter : BaseAdapter<Contact>
{
    private readonly Context _context;
    private List<Contact> _contactList;

    public AllContactsListAdapter(Context context, List<Contact> contacts)
    {
        _context = context;
        // 初始化空列表避免空引用
        _contactList = contacts ?? new List<Contact>();
    }

    // 新增:批量添加联系人的方法
    public void AddNewContacts(IEnumerable<Contact> newContacts)
    {
        if (newContacts == null) return;
        _contactList.AddRange(newContacts);
    }

    // 重写BaseAdapter的必备方法
    public override int Count => _contactList.Count;

    public override Contact this[int position] => _contactList[position];

    public override long GetItemId(int position) => position;

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        // 这里保留你原有的Item视图渲染逻辑即可
        // ...
    }
}

第二步:在页面中复用适配器,实现加载更多

在你的Activity/Fragment中,初始化一次适配器后就不再重新创建,而是直接调用适配器的添加方法,再通知数据变化:

private List<Contact> _allContacts;
private AllContactsListAdapter _adapter;
private ListView _contactListView;
private bool _isLoading = false; // 防止重复触发加载请求

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    SetContentView(Resource.Layout.your_contact_layout);

    _contactListView = FindViewById<ListView>(Resource.Id.listView_contacts);
    _allContacts = new List<Contact>();

    // 加载初始数据并初始化适配器
    LoadInitialContacts();

    // 监听ListView滚动事件,判断是否到底部
    _contactListView.Scroll += OnListViewScroll;
}

// 加载初始联系人数据
private void LoadInitialContacts()
{
    // 从数据库获取第一页数据,比如前20条
    var initialContacts = FetchContactsFromDb(0, 20);
    _allContacts.AddRange(initialContacts);
    
    // 只初始化一次适配器
    _adapter = new AllContactsListAdapter(this, _allContacts);
    _contactListView.Adapter = _adapter;
}

// ListView滚动监听
private void OnListViewScroll(object sender, AbsListView.ScrollEventArgs e)
{
    var listView = sender as ListView;
    if (listView == null || _isLoading) return;

    // 判断是否滚动到最后一项
    int lastVisiblePos = listView.LastVisiblePosition;
    int totalItems = listView.Count;
    
    if (lastVisiblePos == totalItems - 1 && totalItems > 0)
    {
        // 触发加载更多
        LoadMoreContacts();
    }
}

// 加载更多联系人
private void LoadMoreContacts()
{
    _isLoading = true;
    // 从当前已加载的数量开始,加载下一页数据(比如再加载20条)
    var newContacts = FetchContactsFromDb(_allContacts.Count, 20);
    
    if (newContacts != null && newContacts.Any())
    {
        // 1. 给适配器添加新数据
        _adapter.AddNewContacts(newContacts);
        // 2. 同步更新外部的数据源(可选,但保持同步更稳妥)
        _allContacts.AddRange(newContacts);
        // 3. 通知适配器数据已变化,ListView会自动渲染新增项
        _adapter.NotifyDataSetChanged();
    }
    else
    {
        Toast.MakeText(this, "没有更多联系人了", ToastLength.Short).Show();
    }
    
    _isLoading = false;
}

// 模拟从数据库分页获取数据的方法
private List<Contact> FetchContactsFromDb(int startIndex, int pageSize)
{
    // 这里替换成你的数据库分页查询逻辑
    // 示例:从startIndex开始,查询pageSize条记录
    // ...
    return new List<Contact>();
}

关键注意事项

  • 不要重复设置Adapter:初始化一次后,后续只需要更新数据源并调用NotifyDataSetChanged()即可,ListView会自动刷新新增的项,避免不必要的性能消耗。
  • 防止重复加载:添加_isLoading标志,避免用户快速滚动时多次触发加载请求。
  • 封装数据源操作:通过Adapter的公共方法添加数据,而不是直接修改Adapter的私有列表,这样代码更健壮,也符合面向对象的设计原则。

内容的提问来源于stack exchange,提问作者Thamarai T

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:18:16