【问题标题】:Update custom listviewAdapter更新自定义列表视图适配器
【发布时间】:2020-04-29 13:11:53
【问题描述】:

我想将新数据添加到我的 listviewAdapter,我尝试清除它之前的所有数据并通知现在有数据,但它似乎不起作用。我关注了Solution (stackoverflow),但它不起作用。

有人知道为什么吗?

public class ReportsListViewAdapter : BaseAdapter<IMobileReport>, IFilterable
{
    internal List<IMobileReport> originalData;
    internal List<IMobileReport> reports;
    private Context context;
    public override IMobileReport this[int position] => reports[position];

    public ReportsListViewAdapter(Context context, IEnumerable<IMobileReport> reports)
    {
        this.reports = reports.OrderBy(report => report.StudyDate).ToList();
        this.context = context;
        Filter = new ReportsFilter(this);
    }

    public override int Count => this.reports.Count;
    public Filter Filter { get; private set; }
    public override long GetItemId(int position)
    {
        return position;
    }

    public void updateReportsList(List<MobileReport> newlist)
    {
        reports.AddRange(newlist);
        this.NotifyDataSetChanged();
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View row = convertView;
        if(row == null)
        {
            row = LayoutInflater.From(context).Inflate(Resource.Layout.listView_reports_row, null, false);
        }

        var txtName = row.FindViewById<TextView>(Resource.Id.txtName);
        txtName.Text = reports[position].Student.Name;

        var txtFirstName = row.FindViewById<TextView>(Resource.Id.txtFirstName);
        txtFirstName.Text = reports[position].Student.FirstName;

        var txtSource = row.FindViewById<TextView>(Resource.Id.txtSource);
        txtSource.Text = reports[position].Source;
        var txtCritical = row.FindViewById<TextView>(Resource.Id.txtCritical);
        txtSource.Text = reports[position].Critical.ToString();
        return row;

    }
}


protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        reports = new List<IMobileReport>();
        //Init();
        _reportsHubConnector = new ReportsHubConnector();

        #pragma warning disable 4014 // We cannot await this task here because the signature of the inherited method is void
        Task.Factory.StartNew(async () =>
        {
            await _reportsHubConnector.StartConnection();
            await _reportsHubConnector.SendT();

        }, TaskCreationOptions.PreferFairness);
        #pragma warning restore 4014

        Console.WriteLine("HomeActivity: OnCreate");
        SetContentView(Resource.Layout.activity_reports);
        SupportActionBar.SetDisplayShowTitleEnabled(false);
        SupportActionBar.SetDisplayHomeAsUpEnabled(false);
        SupportActionBar.SetDisplayShowHomeEnabled(true);

        WireUpElements();

        listView = FindViewById<ListView>(Resource.Id.reports);
        ReportsListViewAdapter adapter = new ReportsListViewAdapter(this, reports);

        listView.Adapter = adapter;

        searchView = FindViewById<SearchView>(Resource.Id.searchView1);
        searchView.QueryTextChange += this.Filter;

        listView.ItemClick += ItemClicked;

        criticalButton = FindViewById<LinearLayout>(Resource.Id.AuthenticatorButton);
        criticalButton.Click += criticalClicked;

        _reportsHubConnector.ReportsRecieved += (reports) =>
        {
            adapter.updateReportsList(reports);

        };
    }

当我慢慢调试时,GetView 确实会被触发,也许这是我不快速调试或检查代码时为什么不调用它的线索。

This.RunOnUiThread 从未被调用,但 update 被调用。

 _reportsHubConnector.ReportsRecieved += (tmpReports) =>
 {
       adapter.updateReportsList(tmpReports);
       this.RunOnUiThread(() =>
       {

            criticalButton.SetBackgroundColor(Android.Graphics.Color.Red);
        });
  };

【问题讨论】:

    标签: xamarin.android listview-adapter


    【解决方案1】:

    我尝试清除它之前的所有数据并通知现在有数据但它似乎不起作用。

    在共享代码中,没有看到明确的方法,可以加reports.Clear()查看是否有效。

    public void updateReportsList(List<MobileReport> newlist)
    {
        reports.Clear();
        reports.AddRange(newlist);
        this.NotifyDataSetChanged();
    }
    

    如果不行,需要检查newlist添加的数据格式是否正确。

    ========================更新====================== ==

    OnCreate方法中,其中_reportsHubConnector.ReportsRecieved调用更新方法修改如下:

    _reportsHubConnector.ReportsRecieved += (tmpReports) =>
    {
        adapter.updateReportsList(tmpReports);
    
    };
    

    reports 参数更改为tmpReports 以避免与原始数据reports 混合。

    因此,还有另一种常见的方式来更新适配器的数据:

    _reportsHubConnector.ReportsRecieved += (reports) =>
    {
        List<IMobileReport> tmp = new List<IMobileReport>();
        tmp =  reports ; // use a tmp list data for updating , not using original list data 
        adapter.updateReportsList(tmp);
    
    };
    

    =============================更新================== ==============

    从我的示例项目中,我发现了一个有趣的现象,这可能是问题所在。

    在这里我将分享我的自定义适配器HomeScreenAdapter

    public class HomeScreenAdapter : BaseAdapter<TableItem> {
        List<TableItem> items;
        Activity context;
        public HomeScreenAdapter(Activity context, List<TableItem> items)
            : base()
        {
            this.context = context;
            this.items = new List<TableItem>();
            this.items.AddRange(items);
            //this.items = items;
        }
        public override long GetItemId(int position)
        {
            return position;
        }
        public override TableItem this[int position]
        {
            get { return items[position]; }
        }
        public override int Count
        {
            get { return items.Count; }
        }
        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            var item = items[position];
    
            View view = convertView;
            if (view == null) // no view to re-use, create new
                view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
            view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
            view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading+" items";
            view.FindViewById<ImageView>(Resource.Id.Image).SetImageResource(item.ImageResourceId);
    
            return view;
        }
    
        public void UpdateListView(List<TableItem> newTableItem)
        {
            items.Clear();
            items.AddRange(newTableItem);
            NotifyDataSetChanged();
        }
    }
    

    你会在HomeScreenAdapterConstructor看到,我注释了这行代码this.items = items;。它会起作用的原因:

    然而,如果我用this.items = items;代替this.items.AddRange(items);,它不会更新任何东西,甚至在ListView中不能显示任何东西。

    public HomeScreenAdapter(Activity context, List<TableItem> items)
        : base()
    {
        this.context = context;
        this.items = new List<TableItem>();
        //this.items.AddRange(items);
        this.items = items;
    }
    

    效果:

    可能的原因

    如果这里使用等号,项目的指针地址会发生变化。数据更新时,不能指向原来的数据源,所以不能更新成功。

    因此,这里Constructor你的代码可以修改如下,看看是否有效:

    public ReportsListViewAdapter(Context context, IEnumerable<IMobileReport> reports)
    {
        //this.reports = reports.OrderBy(report => report.StudyDate).ToList();
        this.reports =  new List<IMobileReport>();
        this.reports.AddRange(reports.OrderBy(report => report.StudyDate).ToList());
        this.context = context;
        Filter = new ReportsFilter(this);
    }
    

    相关:这里是the sample project link

    【讨论】:

    • Okey,更新时出现什么现象?是否发生错误信息或其他日志信息?
    • 调用 NotifyDataSetChanged 后没有出现错误,我确实看到他触发了适配器的计数和位置,但视图没有更新
    • GetView 没有被调用,所以它不会更新我猜的视图
    • @Max 能否分享一下调用update方法的代码?
    • 我读到你需要调用 RunOnUiThread 但是当我这样做时。RunOnUiThread 它没有被调用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-21
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多