【问题标题】:Android Chat Application : Message Adapter does not update the items in list view correctlyAndroid 聊天应用程序:消息适配器无法正确更新列表视图中的项目
【发布时间】:2017-07-26 23:45:29
【问题描述】:

这是我在 Stack Overflow 上的第一个问题,我一直在 Android 上构建一个简单的聊天应用程序,它从在线数据库加载聊天历史记录,并将使用自定义消息适配器显示在列表视图中。

这是程序的当前状态:

Demo

但是,数组列表下第 6 条聊天消息后,列表项的布局不正确,并且后面的所有聊天消息都在重复前 6 条消息的布局。

这是我的适配器的代码:

public class messageAdapter extends ArrayAdapter<chatMessage> {

private Activity activity;
private List<chatMessage> messages;

public messageAdapter(Activity context, int resource, List<chatMessage> objects) {
    super(context, resource, objects);
    this.activity = context;
    this.messages = objects;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

    int layoutResource = 0; // determined by view type
    chatMessage chatMessage = getItem(position);
    int viewType = getItemViewType(position);

    if (chatMessage.isMine()) {
        layoutResource = R.layout.chat_bubble_right;
    } else {
        layoutResource = R.layout.chat_bubble_left;
    }

    if (convertView != null) {
        holder = (ViewHolder) convertView.getTag();
    } else {
        convertView = inflater.inflate(layoutResource, parent, false);
        holder = new ViewHolder(convertView);
        convertView.setTag(holder);
        Log.d("ViewID", "generated");
    }

    //set message content
    holder.message.setText(chatMessage.getContent());

    return convertView;
}

@Override
public int getViewTypeCount() {
    // return the total number of view types. this value should never change
    // at runtime
    return 2;
}

@Override
public int getItemViewType(int position) {
    // return a value between 0 and (getViewTypeCount - 1)
    return position % 2;
}

private class ViewHolder {
    private TextView message;

    public ViewHolder(View v) {
        message = (TextView) v.findViewById(R.id.txt_msg);
    }
}

这是我将聊天消息加载到数组列表中的方法:

private class getChatHistory extends AsyncTask<DBConnection,Long,JSONArray> {
    @Override
    protected JSONArray doInBackground(DBConnection... params) {
        return params[0].getChatHistory(userID);
    }

    @Override
    protected void onPostExecute(JSONArray jsonArray) {

        chatData = jsonArray;

        if (chatData != null)
        {
            for (int i = 0; i < chatData.length(); i++)
            {
                JSONObject currentItem = null;

                try
                {
                    currentItem = chatData.getJSONObject(i);
                    int msgID = currentItem.getInt("MessageID");
                    String currentText = currentItem.getString("MessageContent");
                    int senderID = currentItem.getInt("SenderID");
                    int receiverID = currentItem.getInt("ReceiverID");
                    chatMessage currentMessage = new chatMessage(currentText, senderID, userID);
                    Log.d("Is Mine", Boolean.toString(currentMessage.isMine()));
                    messageHistory.add(currentMessage);
                    DBAdapter.notifyDataSetChanged();

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这是我从我运行的 PHP 文件中获得的 JSONArray:

[{"MessageID":"1","SenderID":"1","ReceiverID":"8","Duration":"2.4","MessageContent":"agnblean liajiaj vliwv fla","MessageLength":"26","Status":"received","Date":"2016-04-04 14:00:00"},
{"MessageID":"2","SenderID":"8","ReceiverID":"1","Duration":"3.1","MessageContent":"akwuehrgeubwfcofawve","MessageLength":"20","Status":"received","Date":"2016-04-04 17:00:00"},
{"MessageID":"3","SenderID":"8","ReceiverID":"1","Duration":"3.1","MessageContent":"akwuehrgeubwfjurawve","MessageLength":"20","Status":"received","Date":"2016-04-04 17:00:05"},
{"MessageID":"4","SenderID":"8","ReceiverID":"1","Duration":"3.1","MessageContent":"akwuehrgeubwalwrawve","MessageLength":"20","Status":"received","Date":"2016-04-04 17:00:10"},
{"MessageID":"5","SenderID":"1","ReceiverID":"8","Duration":"3.1","MessageContent":"akwuehrgeubwalwrawve","MessageLength":"20","Status":"received","Date":"2016-04-04 17:01:10"},
{"MessageID":"8","SenderID":"1","ReceiverID":"8","Duration":"4.6","MessageContent":"vsjkgkgredjegwhkaga","MessageLength":"23","Status":"received","Date":"2016-04-05 05:00:00"},
{"MessageID":"9","SenderID":"8","ReceiverID":"1","Duration":"5.2","MessageContent":"agrlanwligna","MessageLength":"21","Status":"received","Date":"2016-04-06 00:00:00"},
{"MessageID":"10","SenderID":"8","ReceiverID":"1","Duration":"7.2","MessageContent":"akewgaughurawaarg","MessageLength":"12","Status":"received","Date":"2016-04-12 00:00:00"},
{"MessageID":"11","SenderID":"1","ReceiverID":"8","Duration":"7.2","MessageContent":"wgkakjrgnjange","MessageLength":"41","Status":"received","Date":"2016-04-15 00:00:00"},
{"MessageID":"12","SenderID":"1","ReceiverID":"8","Duration":"4.67","MessageContent":"yikes","MessageLength":"5","Status":"received","Date":"2016-04-21 00:00:00"},
{"MessageID":"13","SenderID":"8","ReceiverID":"1","Duration":"8.2","MessageContent":"iobanoine","MessageLength":"4","Status":"received","Date":"2016-04-30 00:00:00"}]

所以我认为这将为聊天历史记录生成正确的布局,其中活动用户是用户 ID = 1,所有发件人 ID = 1 的消息都应该在列表视图的右侧,但是相反,我得到了这个:

screenshot

这是列表视图中第 5-8 个元素的截图,但是第 7 个元素在右侧而不是在左侧,后面的元素继续重复前 6 个元素的模式。我已经检查了转换视图的日志,它只显示了 6 次,这是否与此错误有关?以及如何解决适配器无法正确定位列表项资源的问题?

编辑:我已将 getItemViewType() 的覆盖更改为此

@Override
public int getItemViewType(int position) {
    chatMessage chatMessage = getItem(position);
    if (chatMessage.isMine()) {
        return 0;
    } else {
        return 1;
    }
}

我还删除了getViewTypeCount的覆盖方法,并在getView()方法中稍微改变了条件:

int viewType = getItemViewType(position);

    if (viewType==0) {
        layoutResource = R.layout.chat_bubble_right;
    } else {
        layoutResource = R.layout.chat_bubble_left;
    }

现在聊天消息列表的顺序正常到第8个元素,然后顺序又变错了。

编辑 2

我已经跟踪日志中生成的列表项(即新项)的数量,这是我向下滚动到列表视图底部后得到的结果:

04-06 19:23:54.894 11202-11202/com.example.user.normalinterface D/ViewID: generated
04-06 19:23:54.907 11202-11202/com.example.user.normalinterface D/ViewID: generated
04-06 19:23:54.912 11202-11202/com.example.user.normalinterface D/ViewID: generated
04-06 19:23:54.914 11202-11202/com.example.user.normalinterface D/ViewID: generated
04-06 19:23:56.850 11202-11202/com.example.user.normalinterface D/ViewID: generated

这是否与我的问题有关?列表视图中的所有后续记录似乎都在重复列表中前 5 项的模式。

【问题讨论】:

  • 我有一个非常相似的问题,当我找到解决方案时,我会发布我的解决方案。

标签: android listview android-arrayadapter


【解决方案1】:

我认为它来自getViewTypeCount() 方法。在这里,您说您有 2 种不同类型的布局。使用getItemViewType() 方法,您说不同的类型是两条消息中的一条。但是您不会在 getView 方法中使用类型。

显然你不需要这两种类型,所以我建议你只删除这两种方法: getViewTypeCount()getItemViewType()

我认为你不需要它们。

编辑: 您实际上需要这些方法,但是您严重覆盖了getItemViewType

@Override
public int getItemViewType(int position) {
    chatMessage chatMessage = getItem(position);
    if (chatMessage.isMine()) {
        return 0;
    } else {
        return 1;
    }
}

【讨论】:

  • 去掉上面的两个方法后,记录到第8个元素都是正确的,然后布局又变错了……
  • 我已经更改了 getItemViewType() 方法,并且还稍微更改了布局资源的条件,但这很奇怪,因为在调试模式下我已经登录以查看条件是否会给我正确的资源和它工作得很好。不知何故,在第 8 个元素之后资源未正确加载。
  • 我已经发布了更新的适配器方法和当前状态的截图,它仍然无法正常工作。
  • 从我在屏幕截图中看到的是正确的,前 2 条消息由用户 ID 8 发送,另外 2 条消息由用户 ID 1 发送。
  • 对不起,我发布了错误的屏幕截图,但是当我向下滚动时,第 11 个元素不正确。对于消息 ID = 11 而不是在右侧,它在左侧。
【解决方案2】:

根据我的经验,但可能与此无关,您需要在适配器中调用 notifyDataSetChanged(),因此在适配器中设置一个名为 refreshData 的方法,如下所示:

public void refreshData(ArrayList<yourList> data) {
    mValues.clear();
    mValues.addAll(data);
    notifyDataSetChanged();
}

并从您的活动中调用:

mAdapter.refreshData(newData) 

以新数据作为参数。

另外,请确保正确引用适配器类,因此请尝试添加到类的开头:

private final DBAdapter mAdapter;

然后在 getChaHistory 中添加:

mAdapter = DBAdapter

你的适配器有一个正确引用的句柄。请注意对先前答案的更改,您现在调用 mAdapter.refreshData(newData) 而不是 DBAdapter.refreshData(newdata)。真的我认为你应该将适配器传递给班级,我就是这样做的,但你可以试试这种方式,看看你的进展如何?

【讨论】:

  • 我将该方法添加到我的适配器中,但由于某种原因我无法从我的聊天页面类中调用它...
  • 没关系...我将适配器初始化为数组适配器是愚蠢的,这不是我创建的实际适配器类,多么愚蠢的错误,但感谢您的帮助!跨度>
  • 不错,至少你到了那里,伙计!我确实想知道 messageAdapter... :)
  • 但问题依然存在...我还发现列表视图重复了列表中前5项的布局模式,这可能是什么原因造成的?
【解决方案3】:

这将正常工作,但不会那么快。它决定根据值实例化哪个布局,如果“isMine()”如果“isMine() 为真,则实例化包含右对齐 TextView 的布局。否则,实例化另一个布局,(其中 TextView 左对齐)。

@Override
public View getView(int position, View convertView, ViewGroup parent){

    if(messages.get(position).isMine()){
        item = ((Activity)context).getLayoutInflater().inflate(R.layout.chat_bubble_right,null);
    }
    else{
        item = ((Activity)context).getLayoutInflater().inflate(R.layout.chat_bubble_left,null);
    }
    // set the text in the view.
    ((TextView) item.findViewById(R.id.chat_text)).setText(data.get(position).getMessage());
    return item;
}

chat_text id 指的是实例化布局中的 TextView。 (两种布局都包含一个 ID 为 chat_text 的 TextView)。
我将此 Google IO 事件用作资源:
https://www.youtube.com/watch?v=wDBM6wVEO70

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-09
    • 1970-01-01
    • 2022-12-13
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多