Android聊天应用程序:消息适配器未正确更新列表视图中的项目

Android聊天应用程序:消息适配器未正确更新列表视图中的项目,android,listview,android-arrayadapter,Android,Listview,Android Arrayadapter,这是我在Stack Overflow中的第一个问题,我一直在Android上构建一个简单的聊天应用程序,它从在线数据库加载聊天历史记录,并使用定制的消息适配器将其显示在列表视图中 以下是程序的当前状态: 但是,在阵列列表的第6条聊天消息之后,列表项的布局不正确,并且以下所有聊天消息都重复了前6条消息的布局 以下是我的适配器的代码: public class messageAdapter extends ArrayAdapter<chatMessage> { private Act

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

以下是程序的当前状态:

但是,在阵列列表的第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);
    }
}
因此,我认为这将为聊天历史生成正确的布局,其中活动用户为用户ID=1,发件人ID=1的所有消息应位于列表视图的右侧,但我得到了以下结果:

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

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

@Override
public int getItemViewType(int position) {
    chatMessage chatMessage = getItem(position);
    if (chatMessage.isMine()) {
        return 0;
    } else {
        return 1;
    }
}
我还删除了getViewTypeCount的覆盖方法,并在getView()方法中稍微更改了条件:

现在聊天信息列表在第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项的模式。

我认为它来自
getViewTypeCount()
方法。这里你说你有两种不同类型的布局。使用方法
getItemViewType()。但是在getView方法中不使用事件类型

显然,您不需要这两种类型,因此我建议您删除这两种方法:
getViewTypeCount()
getItemViewType()

我认为你不需要它们

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

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

我认为它来自
getViewTypeCount()
方法。这里你说你有两种不同类型的布局。使用方法
getItemViewType()。但是在getView方法中不使用事件类型

显然,您不需要这两种类型,因此我建议您删除这两种方法:
getViewTypeCount()
getItemViewType()

我认为你不需要它们

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

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

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

public void refreshData(ArrayList<yourList> data) {
    mValues.clear();
    mValues.addAll(data);
    notifyDataSetChanged();
}
以新数据作为参数

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

private final DBAdapter mAdapter;
然后在getChaHistory中添加:

mAdapter = DBAdapter

这样做的目的是为适配器提供一个正确引用的句柄。请注意对前面答案的更改,您现在调用mAdapter.refreshData(newData)而不是DBAdapter.refreshData(newData)。实际上,我认为您应该将适配器传递给类,我就是这么做的,但您可以尝试这种方式,看看您的情况如何?

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

public void refreshData(ArrayList<yourList> data) {
    mValues.clear();
    mValues.addAll(data);
    notifyDataSetChanged();
}
以新数据作为参数

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

private final DBAdapter mAdapter;
然后在getChaHistory中添加:

mAdapter = DBAdapter

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

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

chat_text id指的是实例化版面中的文本视图。(两个版面都包含id为chat_text的文本视图)。
我将此Google IO事件用作资源:

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

聊天室文本id指的是实例化布局中的文本视图。(两种布局都包含id为chat_text的文本视图)。
我将此Google IO事件用作资源:

删除上面的两个方法后,记录直到第8个元素都是正确的,然后布局再次变得不正确……我更改了getItemViewType()方法,还稍微更改了布局资源的条件,但奇怪的是,在调试模式下,我已记录以查看
@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;
}