【问题标题】:Update listview from API call in certain interval- xamarin.forms在特定时间间隔内从 API 调用更新列表视图 - xamarin.forms
【发布时间】:2020-04-06 20:10:26
【问题描述】:

我正在 xamarin.forms 中开发一个聊天应用程序。绑定到我的聊天列表视图页面的视图模型有一个 API 调用,它将获取聊天数据并绑定到列表视图。该 API 只会调用一次,即;当我们打开页面时。我想要做的是每 10 秒调用一次 API 并在有新消息时更新列表视图。但是发生的事情不是更新列表,而是复制整个数据。我认为如果再次调用 API 是正常的,它将重新绑定整个数据。如果有任何新消息可用,如何使此更新成为列表视图?就像聊天应用程序一样。感谢任何帮助或指导。

API 数据将根据参数分配给传入和传出单元格。

我的视图模型;

 public class ChatPageViewModel : INotifyPropertyChanged
    { 
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public INavigation Navigation { get; set; }
        public string APropertyToSet { get; set; }

        public ObservableCollection<NCMessage> Messages { get; set; } = new ObservableCollection<NCMessage>();
        public ObservableCollection<ChatData> ChatListObj { get; set; }
        public ChatPageViewModel(INavigation navigation)
        {

            // This is how I call the timer

            Device.StartTimer(TimeSpan.FromSeconds(10), () =>
            {

                Device.BeginInvokeOnMainThread(async () =>
                {
                    await loadChatList();
                });

                return true;
            });



            // <--------------- Load chat List API-------------------->


            async Task loadChatList()
            {
                await Task.Run(async () =>
                {
                    try
                    {
                    // API call is the dedicated class for makin API call               
                    APICall callForNotificationList = new APICall("apicallUrl/CallChatList", null, null, "GET");
                        try
                        {
                            ChatListObj = callForNotificationList.APICallResult<ObservableCollection<ChatData>>();
                            if (ChatListObj[0].results.Count != null && ChatListObj[0].results.Count != 0)
                            {
                                if (ChatListObj[0].success)
                                {


                                    foreach (var item in ChatListObj[0].results)
                                    {
                                        if (item.type == "user")
                                        {
                                            if (!string.IsNullOrEmpty(item.message))
                                            {
                                                var message = new NCMessage
                                                {
                                                    Text = item.message.ToString(),
                                                    IsIncoming = "True"
                                                };
                                                Messages.Add(message);

                                            }
                                        }
                                    }
                                }
                                else
                                {
                                //error message
                            }
                            }

                            else
                            {
                            //error message
                        }

                        }
                        catch (Exception e)
                        {

                        }

                    }
                    catch (Exception ex)
                    {

                    }
                });
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

我的聊天 XAML

 <ListView                      
             ItemTemplate="{StaticResource MessageTemplateSelector}" 
             ItemsSource="{Binding Messages,Mode=OneWay}" 
             Margin="0"     
             BackgroundColor="Transparent"
             SelectionMode="None"                                  
             FlowDirection="RightToLeft"                               
             HasUnevenRows="True" x:Name="ChatList"
             VerticalOptions="FillAndExpand" 
             SeparatorColor="Transparent"
             >
            </ListView>

我的 XAML.cs

public partial class ChatPage : ContentPage
    {
        ChatPageViewModel vm;
        public ChatPage()
        {
            InitializeComponent();
            this.BindingContext = vm = new ChatPageViewModel(Navigation);
        }
        protected async override void OnAppearing()
        {
            base.OnAppearing();
            await Task.Delay(2000);
            await vm.loadChatList();
        }   
    }

【问题讨论】:

    标签: xamarin xamarin.forms


    【解决方案1】:

    您正在为从 API 检索到的每条消息执行此操作,而不检查该消息是否已在集合中

    Messages.Add(message);
    

    你有(至少)三个选项

    1. 在调用 API 之前清除整个 Messages 集合
    2. 在将消息添加到集合之前检查消息是否存在
    3. 修改 API 调用以仅返回新消息

    【讨论】:

    • 感谢 jason 的回复。如何实现第二个选项?
    • 如果我清除整个消息,它看起来会很难看吗?比如消息突然消失之类的?
    • 使用 IndexOf 方法或 LINQ 查询来检查消息是否存在。不知道使用 Clear 会如何影响您的 UI,您需要对其进行测试。请记住,如果您的 API 每次都返回每条消息,那么每次后续调用都会变长
    • Device.StartTimer(TimeSpan.FromSeconds(10), () => { Device.BeginInvokeOnMainThread(async () => { vm.Messages.Clear(); await vm.loadChatList(); } ); 返回 true; });
    • 但它给了我索引超出范围异常
    【解决方案2】:

    通常的聊天系统使用套接字连接工作,因此服务器可以push 只接收它收到的新消息,而不是您当前基于pull 的系统。如果你想走这条路,看看SignalR,这是一个很好的例子 - Real Time Chat App

    至于你目前的代码,有几种可能:

    1. 正如@Jason 所提到的,您可以清除现有消息并重新添加所有消息,您应该使用RangeObservableCollection 这样它就不会在每次添加消息时都重新绘制列表
    2. 您可以为所有聊天消息维护一个 Id 并在 API 调用中发送该 Id,理想情况下,过滤应该发生在服务器端,客户端没有额外负载。
    new APICall("apicallUrl/CallChatList?from_id=<last_message_id>", null, null, "GET")
    

    如果没有last_message_id,则发送所有数据。这消除了不必要的数据传输,因为与之前的 10k 条消息相比,您只发送 1 条新消息:)

    【讨论】:

    • 感谢您的回复。你能指导我清除数据吗?我试图清除这样的数据
    • Device.StartTimer(TimeSpan.FromSeconds(10), () => { Device.BeginInvokeOnMainThread(async () => { await loadChatList(); Messages.Clear(); }); return true ; });
    • 但是它会抛出关于索引超出范围的异常。
    • 我按照你的建议使用了这个 Rangeobservable 集合。但清除部分效果不佳
    • 我不认为抛出异常很清楚。您正在异步函数中创建一个新线程,该线程取消了 BeginInvokeOnMainThread。要对其进行测试,请删除 Messages.Clear() 并运行它,应用仍应崩溃。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 2018-10-30
    相关资源
    最近更新 更多