【问题标题】:list only updates when I scroll - android listview列表仅在我滚动时更新 - android listview
【发布时间】:2016-06-15 20:34:09
【问题描述】:

我正在尝试构建一个使用列表视图来显示消息的聊天应用程序。我正在使用 SignalR 进行实时通信。我遇到的问题是,listview 适配器仅在我滚动时更新接收方端的列表,但在发送方端,消息立即显示。 这是该聊天的活动:

 protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        ISharedPreferences pref = Application.Context.GetSharedPreferences("UserInfo", FileCreationMode.Private);
        loggeduser = pref.GetString("Username", String.Empty);



        SetContentView(Resource.Layout.chat_activity);

        initControls();
    }

    private async void initControls()
    {
        SignalRClientHelper proxySubscriber = SignalRClientHelper.GetInstance();
        await proxySubscriber.StartConnection();
        proxySubscriber.OnMessageReceived += proxySubscriber_OnMessageReceived;

        messagesContainer = FindViewById<ListView>(Resource.Id.messagesContainer);
        messageET = FindViewById<EditText>(Resource.Id.messageEdit);
        sendBtn = FindViewById<Button>(Resource.Id.chatSendButton);

        adapter = new ChatAdapter(this, new List<ChatMessage>(), loggeduser);
        messagesContainer.Adapter = adapter;

        //loadDummyHistory();

        sendBtn.Click += (o, e) =>
        {
            string messageText = messageET.Text.ToString();
            if (TextUtils.IsEmpty(messageText))
            {
                return;
            }

            proxySubscriber.InvokeSendMessage("psyoptica", messageText);

            ChatMessage chatMessage = new ChatMessage();
            chatMessage.Message = messageText;
            chatMessage.Username = loggeduser;

            messageET.Text = "";

            displayMessage(chatMessage);
        };

        RelativeLayout container = FindViewById<RelativeLayout>(Resource.Id.container);
    }

    void proxySubscriber_OnMessageReceived(string username, string message)
    {
        ChatMessage chatMessage = new ChatMessage { Username = username, Message = message };
        displayMessage(chatMessage);

    }

    public void displayMessage(ChatMessage message)
    {
        adapter.add(message);
        adapter.NotifyDataSetChanged();
        scroll();
    }

    private void scroll()
    {
        messagesContainer.SetSelection(messagesContainer.Count - 1);
    }


}

这是列表视图适配器的代码:

class ChatAdapter : BaseAdapter
{
    private List<ChatMessage> messages;
    private Activity context;
    private string loggedUsername;

    public ChatAdapter(Activity context, List<ChatMessage> messages, string loggedUsername)
    {
        this.messages = messages;
        this.context = context;
        this.loggedUsername = loggedUsername;
    }
    public override int Count
    {
        get { return messages.Count; }
    }

    public override Java.Lang.Object GetItem(int position)
    {
        return null;
    }

    public override long GetItemId(int position)
    {
        return position;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        View view;
        ViewHolder holder;

        if (convertView == null)
        {
            view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.chatMessage, parent, false);
            holder = createViewHolder(view);
        }
        else
        {
            view = convertView;
            holder = createViewHolder(view);
        }

        bool isMe = messages[position].Username == loggedUsername;

        setAlignment(holder, isMe);

        holder.txtMessage.Text = messages[position].Message;

        return view;
    }

    private void setAlignment(ViewHolder holder, bool isMe)
    {
        if (!isMe)
        {
            holder.contentWithBG.SetBackgroundResource(Resource.Drawable.in_message_bg);

            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)holder.contentWithBG.LayoutParameters;
            layoutParams.Gravity = GravityFlags.Right;
            holder.contentWithBG.LayoutParameters = layoutParams;

            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)holder.content.LayoutParameters;
            lp.AddRule(LayoutRules.AlignParentLeft, 0);
            lp.AddRule(LayoutRules.AlignParentRight);

            holder.content.LayoutParameters = lp;

            layoutParams = (LinearLayout.LayoutParams)holder.txtMessage.LayoutParameters;
            layoutParams.Gravity = GravityFlags.Right;
            holder.txtMessage.LayoutParameters = layoutParams;
        }
        else
        {
            holder.contentWithBG.SetBackgroundResource(Resource.Drawable.out_message_bg);

            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)holder.contentWithBG.LayoutParameters;
            layoutParams.Gravity = GravityFlags.Left;
            holder.contentWithBG.LayoutParameters = layoutParams;

            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)holder.content.LayoutParameters;
            lp.AddRule(LayoutRules.AlignParentRight, 0);
            lp.AddRule(LayoutRules.AlignParentLeft);

            holder.content.LayoutParameters = lp;

            layoutParams = (LinearLayout.LayoutParams)holder.txtMessage.LayoutParameters;
            layoutParams.Gravity = GravityFlags.Left;
            holder.txtMessage.LayoutParameters = layoutParams;
        }
    }

    public void add(ChatMessage message)
    {
        messages.Add(message);
    }

    public void add(List<ChatMessage> chatMessages)
    {
        messages.AddRange(chatMessages);
    }

    private ViewHolder createViewHolder(View v)
    {
        ViewHolder holder = new ViewHolder();
        holder.txtMessage = v.FindViewById<TextView>(Resource.Id.txtMessage);
        holder.content = v.FindViewById<LinearLayout>(Resource.Id.content);
        holder.contentWithBG = v.FindViewById<LinearLayout>(Resource.Id.contentWithBackground);
        holder.txtInfo = v.FindViewById<TextView>(Resource.Id.txtInfo);
        return holder;
    }

    private class ViewHolder
    {
        public TextView txtMessage { get; set; }
        public TextView txtInfo { get; set; }
        public LinearLayout content { get; set; }
        public LinearLayout contentWithBG { get; set; }

    }

}

每次有新消息添加到列表时,都会调用方法displayMessage()。我不明白为什么我必须滚动才能在接收器端显示更改。谁能指出我的代码中的错误?

【问题讨论】:

  • 我不知道我是否理解这个问题,您正在更新列表,将元素添加到列表视图的最后位置,这就是为什么您需要滚动才能看到它。
  • 是但不应该“messagesContainer.SetSelection(messagesContainer.Count - 1);”自动滚动以显示列表中的最后一项?此外,即使列表为空,列表项也不会出现,我必须滚动才能显示新添加的项。
  • 请检查我的答案

标签: android listview


【解决方案1】:

尝试使用 scrollToPosition() 代替 setSelection() 和适配器 notifyDataSetChanged() 中的 add() 方法;

在你的课堂上 ChatAdapter:

public void add(ChatMessage message)
{ 
    messages.Add(message);
    NotifyDataSetChanged();
}

public void add(List<ChatMessage> chatMessages)
{
    messages.AddRange(chatMessages);
    NotifyDataSetChanged();
}

尝试在 proxySubscriber_OnMessageReceived() 中运行进程:

 void proxySubscriber_OnMessageReceived(string username, string message)
{
   runOnUiThread(new Runnable() {
    @Override
    public void run() {
     ChatMessage chatMessage = new ChatMessage { Username = username, Message = message };
     displayMessage(chatMessage);
    }
   });


}

【讨论】:

  • 没有得到您答案的第二部分。我应该在适配器的add()方法中做“notifyDataSetChanged()”吗?
  • 没有。我不认为这是滚动的问题,因为当不需要滚动时项目应该出现。如果您看到点击事件“sendBtn.Click”,我使用的是相同的方法“displayMessage()”,当有来自服务器的回调但列表刷新点击事件而不是服务器端时事件。
  • 此问题与此处的问题“stackoverflow.com/questions/16436542/…”类似,但我认为该解决方案不适用于我的情况。
  • 嗯,我明白了,因为它可能是一个异步进程,您需要在 uithread 上运行 displayMessage();方法。我再次更新了答案。
  • 是的。这行得通。也许来自服务器的响应在单独的线程上运行。在 UI 线程中更新列表有效。不能感谢你我的兄弟! :)
猜你喜欢
  • 1970-01-01
  • 2018-10-04
  • 2019-06-27
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
  • 2011-04-06
  • 1970-01-01
相关资源
最近更新 更多