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