1

下面是我完整的 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);
}
4

3 回答 3

1

几个月前我遇到了类似的问题(参考这个 SO Question)ArrayAdapter<MyObject>,除了从BaseAdapter.

因此,将您的适配器的基类更改为ArrayAdapter<MyObject>并实现抽象类的提示方法。您可能需要将一些现有代码移动到这些覆盖的方法以获得更好的性能。

于 2016-06-29T05:46:15.353 回答
1

为您的方法尝试以下代码,

  private static String getDisplayDateTime(Context context, long milli, long milli2) 
  {
      Date date = new Date(milli);
      Date previousDate = new Date(milli2);
      String strCurrentDate = "", strPreviousDate = "";

     if (System.currentTimeMillis() - milli < 60 * 60 * 24 * 1000l) 
     {
        strCurrentDate = DateFormat.getTimeFormat(context).format(date);

        if(milli2 != -1)
            strPreviousDate = DateFormat.getTimeFormat(context).format(previousDate);
        //return strCurrentDate.equals(strPreviousDate) ? "" : strCurrentDate;
     }
     else
     {
       strCurrentDate = DateFormat.getDateFormat(context).format(date) + " " + DateFormat.getTimeFormat(context).format(date);

        if(milli2 != -1)
             strPreviousDate = DateFormat.getDateFormat(context).format(strPreviousDate) + " " + DateFormat.getTimeFormat(context).format(strPreviousDate);
     }
    return strCurrentDate.equals(strPreviousDate) ? "" : strCurrentDate;
 }

现在调用你的方法,如下所示

   if(position > 0)
    {
       final Object previousItem = getItem(position - 1);
       Message previousMessage = (Message) previousItem;

       viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp(), previousMessage.getTimestamp()));
    }
    else
    {
       viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp(), -1));
    }
于 2016-06-29T06:01:48.183 回答
0

您可以通过调用BaseAdapter.notifyDataSetChanged()强制系统重绘所有项目

于 2016-06-26T09:59:43.527 回答