下面是我完整的 sendbird 聊天适配器类。当前日期和时间显示在每条消息中。viewHolder.getView("left_time")
并且viewHolder.getView("right_time")
是用于显示日期和时间的视图,它是在方法中计算的getDisplayDateTime
。我希望仅在日期发生变化时才显示日期和时间。例如,如果有一组日期为 6 月 23 日的消息,则应显示日期和时间仅适用于日期为 6 月 23 日的第一条消息。
我尝试通过将日期存储在 xyz 变量中并将其与每条消息的日期进行比较来检测日期是否发生变化,并且每当它们不相等时,然后使该消息的日期视图可见并将新日期分配给 xyz 变量进行比较带有未来的消息。但是当我向下滚动和向上滚动列表时,这种方法会失败。实现这一目标的理想方法是什么?
public class SendBirdMessagingAdapter extends BaseAdapter {
private static final int TYPE_UNSUPPORTED = 0;
private static final int TYPE_MESSAGE = 1;
private static final int TYPE_SYSTEM_MESSAGE = 2;
private static final int TYPE_FILELINK = 3;
private static final int TYPE_BROADCAST_MESSAGE = 4;
private static final int TYPE_TYPING_INDICATOR = 5;
private final Context mContext;
private final LayoutInflater mInflater;
private final ArrayList<Object> mItemList;
private Hashtable<String, Long> mReadStatus;
private Hashtable<String, Long> mTypeStatus;
private List<MessagingChannel.Member> mMembers;
private long mMaxMessageTimestamp = Long.MIN_VALUE;
private long mMinMessageTimestamp = Long.MAX_VALUE;
public SendBirdMessagingAdapter(Context context) {
mContext = context;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mItemList = new ArrayList<Object>();
mReadStatus = new Hashtable<String, Long>();
mTypeStatus = new Hashtable<String, Long>();
}
@Override
public int getCount() {
return mItemList.size() + ((mTypeStatus.size() <= 0) ? 0 : 1);
}
@Override
public Object getItem(int position) {
if (position >= mItemList.size()) {
ArrayList<String> names = new ArrayList<String>();
for (MessagingChannel.Member member : mMembers) {
if (mTypeStatus.containsKey(member.getId())) {
names.add(member.getName());
}
}
return names;
}
return mItemList.get(position);
}
public void delete(Object object) {
mItemList.remove(object);
}
public void clear() {
mMaxMessageTimestamp = Long.MIN_VALUE;
mMinMessageTimestamp = Long.MAX_VALUE;
mReadStatus.clear();
mTypeStatus.clear();
mItemList.clear();
}
public void resetReadStatus(Hashtable<String, Long> readStatus) {
mReadStatus = readStatus;
}
public void setReadStatus(String userId, long timestamp) {
if (mReadStatus.get(userId) == null || mReadStatus.get(userId) < timestamp) {
mReadStatus.put(userId, timestamp);
}
}
public void setTypeStatus(String userId, long timestamp) {
if (userId.equals(SendBird.getUserId())) {
return;
}
if (timestamp <= 0) {
mTypeStatus.remove(userId);
} else {
mTypeStatus.put(userId, timestamp);
}
}
@Override
public long getItemId(int position) {
return position;
}
public void addMessageModel(MessageModel messageModel) {
if (messageModel.isPast()) {
mItemList.add(0, messageModel);
} else {
mItemList.add(messageModel);
}
updateMessageTimestamp(messageModel);
}
private void updateMessageTimestamp(MessageModel model) {
mMaxMessageTimestamp = mMaxMessageTimestamp < model.getTimestamp() ? model.getTimestamp() : mMaxMessageTimestamp;
mMinMessageTimestamp = mMinMessageTimestamp > model.getTimestamp() ? model.getTimestamp() : mMinMessageTimestamp;
}
public long getMaxMessageTimestamp() {
return mMaxMessageTimestamp == Long.MIN_VALUE ? Long.MAX_VALUE : mMaxMessageTimestamp;
}
public long getMinMessageTimestamp() {
return mMinMessageTimestamp == Long.MAX_VALUE ? Long.MIN_VALUE : mMinMessageTimestamp;
}
public void setMembers(List<MessagingChannel.Member> members) {
mMembers = members;
}
@Override
public int getItemViewType(int position) {
if (position >= mItemList.size()) {
return TYPE_TYPING_INDICATOR;
}
Object item = mItemList.get(position);
if (item instanceof Message) {
return TYPE_MESSAGE;
} else if (item instanceof FileLink) {
return TYPE_FILELINK;
} else if (item instanceof SystemMessage) {
return TYPE_SYSTEM_MESSAGE;
} else if (item instanceof BroadcastMessage) {
return TYPE_BROADCAST_MESSAGE;
}
return TYPE_UNSUPPORTED;
}
@Override
public int getViewTypeCount() {
return 6;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
final Object item = getItem(position);
if (convertView == null || ((ViewHolder) convertView.getTag()).getViewType() != getItemViewType(position)) {
viewHolder = new ViewHolder();
viewHolder.setViewType(getItemViewType(position));
switch (getItemViewType(position)) {
case TYPE_UNSUPPORTED:
convertView = new View(mInflater.getContext());
convertView.setTag(viewHolder);
break;
case TYPE_MESSAGE: {
TextView tv;
CircularImageView iv;
View v;
convertView = mInflater.inflate(R.layout.sendbird_view_messaging_message, parent, false);
v = convertView.findViewById(R.id.left_container);
viewHolder.setView("left_container", v);
iv = (CircularImageView) convertView.findViewById(R.id.img_left_thumbnail);
viewHolder.setView("left_thumbnail", iv);
tv = (TextView) convertView.findViewById(R.id.txt_left);
viewHolder.setView("left_message", tv);
tv = (TextView) convertView.findViewById(R.id.txt_left_name);
viewHolder.setView("left_name", tv);
tv = (TextView) convertView.findViewById(R.id.txt_left_time);
viewHolder.setView("left_time", tv);
v = convertView.findViewById(R.id.right_container);
viewHolder.setView("right_container", v);
iv = (CircularImageView) convertView.findViewById(R.id.img_right_thumbnail);
viewHolder.setView("right_thumbnail", iv);
tv = (TextView) convertView.findViewById(R.id.txt_right);
viewHolder.setView("right_message", tv);
tv = (TextView) convertView.findViewById(R.id.txt_right_name);
viewHolder.setView("right_name", tv);
tv = (TextView) convertView.findViewById(R.id.txt_right_time);
viewHolder.setView("right_time", tv);
tv = (TextView) convertView.findViewById(R.id.txt_right_status);
viewHolder.setView("right_status", tv);
convertView.setTag(viewHolder);
break;
}
case TYPE_SYSTEM_MESSAGE: {
convertView = mInflater.inflate(R.layout.sendbird_view_system_message, parent, false);
viewHolder.setView("message", convertView.findViewById(R.id.txt_message));
convertView.setTag(viewHolder);
break;
}
case TYPE_BROADCAST_MESSAGE: {
convertView = mInflater.inflate(R.layout.sendbird_view_system_message, parent, false);
viewHolder.setView("message", convertView.findViewById(R.id.txt_message));
convertView.setTag(viewHolder);
break;
}
case TYPE_FILELINK: {
TextView tv;
CircularImageView civ;
ImageView iv;
View v;
convertView = mInflater.inflate(R.layout.sendbird_view_messaging_filelink, parent, false);
v = convertView.findViewById(R.id.left_container);
viewHolder.setView("left_container", v);
civ = (CircularImageView) convertView.findViewById(R.id.img_left_thumbnail);
viewHolder.setView("left_thumbnail", civ);
iv = (ImageView) convertView.findViewById(R.id.img_left);
viewHolder.setView("left_image", iv);
tv = (TextView) convertView.findViewById(R.id.txt_left_name);
viewHolder.setView("left_name", tv);
tv = (TextView) convertView.findViewById(R.id.txt_left_time);
viewHolder.setView("left_time", tv);
v = convertView.findViewById(R.id.right_container);
viewHolder.setView("right_container", v);
civ = (CircularImageView) convertView.findViewById(R.id.img_right_thumbnail);
viewHolder.setView("right_thumbnail", civ);
iv = (ImageView) convertView.findViewById(R.id.img_right);
viewHolder.setView("right_image", iv);
tv = (TextView) convertView.findViewById(R.id.txt_right_name);
viewHolder.setView("right_name", tv);
tv = (TextView) convertView.findViewById(R.id.txt_right_time);
viewHolder.setView("right_time", tv);
tv = (TextView) convertView.findViewById(R.id.txt_right_status);
viewHolder.setView("right_status", tv);
convertView.setTag(viewHolder);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(mContext)
.setTitle("Foodvite")
.setMessage("Do you want to download this file?")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
downloadUrl((FileLink) item, mContext);
} catch (IOException e) {
e.printStackTrace();
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create()
.show();
}
});
break;
}
case TYPE_TYPING_INDICATOR: {
convertView = mInflater.inflate(R.layout.sendbird_view_typing_indicator, parent, false);
viewHolder.setView("message", convertView.findViewById(R.id.txt_message));
convertView.setTag(viewHolder);
break;
}
}
}
viewHolder = (ViewHolder) convertView.getTag();
switch (getItemViewType(position)) {
case TYPE_UNSUPPORTED:
break;
case TYPE_MESSAGE:
Message message = (Message) item;
if (message.getSenderId().equals(SendBird.getUserId())) {
viewHolder.getView("left_container", View.class).setVisibility(View.GONE);
viewHolder.getView("right_container", View.class).setVisibility(View.VISIBLE);
displayUrlImage(viewHolder.getView("right_thumbnail", CircularImageView.class), message.getSenderImageUrl(), true);
viewHolder.getView("right_name", TextView.class).setText(message.getSenderName());
viewHolder.getView("right_message", TextView.class).setText(message.getMessage());
viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp()));
int readCount = 0;
for (String key : mReadStatus.keySet()) {
if (key.equals(message.getSenderId())) {
readCount += 1;
continue;
}
if (mReadStatus.get(key) >= message.getTimestamp()) {
readCount += 1;
}
}
if (readCount < mReadStatus.size()) {
if (mReadStatus.size() - readCount > 1) {
viewHolder.getView("right_status", TextView.class).setText("Unread " + (mReadStatus.size() - readCount));
} else {
viewHolder.getView("right_status", TextView.class).setText("Unread");
}
} else {
viewHolder.getView("right_status", TextView.class).setText("");
}
viewHolder.getView("right_container").setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
new AlertDialog.Builder(mContext)
.setTitle("Foodvite")
.setMessage("Do you want to delete a message?")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SendBird.deleteMessage(((Message) item).getMessageId(), new DeleteMessageHandler() {
@Override
public void onError(SendBirdException e) {
e.printStackTrace();
}
@Override
public void onSuccess(long messageId) {
mSendBirdMessagingAdapter.delete(item);
mSendBirdMessagingAdapter.notifyDataSetChanged();
Toast.makeText(mContext, "Message has been deleted.", Toast.LENGTH_SHORT).show();
}
});
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.create()
.show();
return true;
}
});
} else {
viewHolder.getView("left_container", View.class).setVisibility(View.VISIBLE);
viewHolder.getView("right_container", View.class).setVisibility(View.GONE);
displayUrlImage(viewHolder.getView("left_thumbnail", CircularImageView.class), message.getSenderImageUrl(), true);
viewHolder.getView("left_name", TextView.class).setText(message.getSenderName());
viewHolder.getView("left_message", TextView.class).setText(message.getMessage());
viewHolder.getView("left_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp()));
if(isGroupChat)
viewHolder.getView("left_name", TextView.class).setVisibility(View.VISIBLE);
else
viewHolder.getView("left_name", TextView.class).setVisibility(View.GONE);
}
break;
case TYPE_SYSTEM_MESSAGE:
SystemMessage systemMessage = (SystemMessage) item;
viewHolder.getView("message", TextView.class).setText(Html.fromHtml(systemMessage.getMessage()));
break;
case TYPE_BROADCAST_MESSAGE:
BroadcastMessage broadcastMessage = (BroadcastMessage) item;
viewHolder.getView("message", TextView.class).setText(Html.fromHtml(broadcastMessage.getMessage()));
break;
case TYPE_FILELINK:
FileLink fileLink = (FileLink) item;
if (fileLink.getSenderId().equals(SendBird.getUserId())) {
viewHolder.getView("left_container", View.class).setVisibility(View.GONE);
viewHolder.getView("right_container", View.class).setVisibility(View.VISIBLE);
displayUrlImage(viewHolder.getView("right_thumbnail", ImageView.class), fileLink.getSenderImageUrl(), true);
viewHolder.getView("right_name", TextView.class).setText(fileLink.getSenderName());
if (fileLink.getFileInfo().getType().toLowerCase().startsWith("image")) {
displayUrlImage(viewHolder.getView("right_image", ImageView.class), fileLink.getFileInfo().getUrl());
} else {
viewHolder.getView("right_image", CircularImageView.class).setImageResource(R.drawable.sendbird_icon_file);
}
viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, fileLink.getTimestamp()));
int readCount = 0;
for (String key : mReadStatus.keySet()) {
if (key.equals(fileLink.getSenderId())) {
continue;
}
if (mReadStatus.get(key) < fileLink.getTimestamp()) {
readCount += 1;
}
}
if (readCount < mReadStatus.size() - 1) {
viewHolder.getView("right_status", TextView.class).setText("Unread");
} else {
viewHolder.getView("right_status", TextView.class).setText("");
}
} else {
viewHolder.getView("left_container", View.class).setVisibility(View.VISIBLE);
viewHolder.getView("right_container", View.class).setVisibility(View.GONE);
displayUrlImage(viewHolder.getView("left_thumbnail", ImageView.class), fileLink.getSenderImageUrl(), true);
viewHolder.getView("left_name", TextView.class).setText(fileLink.getSenderName());
if (fileLink.getFileInfo().getType().toLowerCase().startsWith("image")) {
displayUrlImage(viewHolder.getView("left_image", ImageView.class), fileLink.getFileInfo().getUrl());
} else {
viewHolder.getView("left_image", CircularImageView.class).setImageResource(R.drawable.sendbird_icon_file);
}
if(isGroupChat)
viewHolder.getView("left_name", TextView.class).setVisibility(View.VISIBLE);
else
viewHolder.getView("left_name", TextView.class).setVisibility(View.GONE);
viewHolder.getView("left_time", TextView.class).setText(getDisplayDateTime(mContext, fileLink.getTimestamp()));
}
break;
case TYPE_TYPING_INDICATOR: {
int itemCount = ((List) item).size();
String typeMsg = ((List) item).get(0)
+ ((itemCount > 1) ? " +" + (itemCount - 1) : "")
+ ((itemCount > 1) ? " are " : " is ")
+ "typing...";
viewHolder.getView("message", TextView.class).setText(typeMsg);
break;
}
}
return convertView;
}
public boolean checkTypeStatus() {
/**
* Clear an old type status.
*/
for (String key : mTypeStatus.keySet()) {
Long ts = mTypeStatus.get(key);
if (System.currentTimeMillis() - ts > 10 * 1000L) {
mTypeStatus.remove(key);
return true;
}
}
return false;
}
private class ViewHolder {
private Hashtable<String, View> holder = new Hashtable<String, View>();
private int type;
public int getViewType() {
return this.type;
}
public void setViewType(int type) {
this.type = type;
}
public void setView(String k, View v) {
holder.put(k, v);
}
public View getView(String k) {
return holder.get(k);
}
public <T> T getView(String k, Class<T> type) {
return type.cast(getView(k));
}
}
}
private static String getDisplayDateTime(Context context, long milli) {
Date date = new Date(milli);
if (System.currentTimeMillis() - milli < 60 * 60 * 24 * 1000l) {
return DateFormat.getTimeFormat(context).format(date);
}
return DateFormat.getDateFormat(context).format(date) + " " + DateFormat.getTimeFormat(context).format(date);
}