RecycleView для корпоративного мессенджера

Пишу корпоративный мессенджер по типу WhatApp'а, вернее клиентскую его часть на Android..

Для отображении сообщений в чате использую стандартный RecycleView, но с разными типами ViewHolder, так как сообщения могут быть разные (входящие, исходящие, удаленные, системный текст и т.д.).

С этим RecycleView у меня постоянные проблемы:

  1. При скролле элементы могут перемешиваться в каком-то случайном порядке. Помогает setRecycle(false).

  2. Если исполнить пункт 1, то нельзя изменять элемент, если сообщение удаляется, то старый View остается на месте, так как его как-бы нельзя удалить

  3. Перемещение к нужному сообщению в чате по позиции (например к закрепленному сообщению) происходит только по .smoothScrollToPosition(), что приводит к порождению событий onScroll, которые я отслеживаю и там своя логика. Мне не надо отслеживать системные перемещения по чату, только пользовательские, но их никак не различить. В общем хотелось бы просто переместиться к позиции в RecycleView без скроллов.

  4. Скролл к последней позиции также происходит не всегда точно, пол сообщения (если одно длинное) остается не доскроленным.

  5. Также хотелось бы получить binding именно на добавление и удаление элементов в RecycleView, то есть имея какой либо Observable<List<?> list>, который привязана к View и при изменении самого list, view тоже реагировала на это, без всяких notifyDataSetChanged

Крайний пункт не самый важный, а остальные меня убивают...

Может быть есть какой-нибудь альтернативные RecycleView, может быть вообще посоветуете что-нибудь другое?

Заранее, спасибо.

Код адаптера

class MessagesAdapter (
    private val messages: MutableList<ChatMessageWrapper>,
    private val chatMessagePopupMenuListener: ChatMessageActionListener
) : RecyclerView.Adapter<AbstractMessageHolder>() {

    override fun getItemViewType(position: Int): Int {
        return messages[position].type.value
    }

    fun getMessages() : MutableList<ChatMessageWrapper> {
        return messages
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AbstractMessageHolder {
        when(ChatMessageType.fromInt(viewType)){
            ChatMessageType.SENT -> {
                val root = LayoutInflater.from(parent.context).inflate(R.layout.chat_message_send_item, parent,false)
                return SentMessageViewHolder(root, chatMessagePopupMenuListener)
            }
            ChatMessageType.RECEIVED -> {
                val root = LayoutInflater.from(parent.context).inflate(R.layout.chat_message_received_item, parent,false)
                return ReceivedMessageViewHolder(root, chatMessagePopupMenuListener)
            }
            ChatMessageType.DELETED_SENT -> {
                val root = LayoutInflater.from(parent.context).inflate(R.layout.chat_message_send_deleted_item, parent,false)
                return DeletedMessageViewHolder(root)
            }
            ChatMessageType.DELETED_RECEIVED -> {
                val root = LayoutInflater.from(parent.context).inflate(R.layout.chat_message_received_deleted_item, parent,false)
                return DeletedMessageViewHolder(root)
            }
            ChatMessageType.SIMPLE_TEXT -> {
                val root = LayoutInflater.from(parent.context).inflate(R.layout.chat_message_simple_text, parent,false)
                return SimpleTextMessageViewHolder(root)
            }
            ChatMessageType.UNKNOWN -> {
                throw IllegalStateException("Unknown type of chat item message")
            }
        }
    }

    fun appendMessage(item: ChatMessageWrapper) {
        var indexOfMsg = -1
        if (item.message is InteractionMessagePacket) {
            indexOfMsg = findIndexOfMessage(item.message.id)
        }
        if (indexOfMsg < 0) {
            messages.add(item)
            notifyItemInserted(messages.size)
        } else {
            messages[indexOfMsg] = item
            notifyItemChanged(indexOfMsg)
        }
    }

    fun appendNewMessagesPack(wrappedMessages: MutableList<ChatMessageWrapper>) {
        messages.addAll(0, wrappedMessages)
        notifyItemRangeInserted(0, wrappedMessages.size)
    }

     fun findIndexOfMessage(itemId: String) : Int {
        val msgInView : ChatMessageWrapper
        try {
            msgInView = messages.filter{it.message is InteractionMessagePacket}.first { (it.message as InteractionMessagePacket).id == itemId }
        } catch (ex: NoSuchElementException) {
            return  -1
        }
        return messages.indexOf(msgInView)
    }

    override fun onBindViewHolder(holder: AbstractMessageHolder, position: Int) {
        val item = messages[position]
        holder.setItem(item.message)
        holder.bind()
        holder.setIsRecyclable(false)
    }

    override fun getItemCount(): Int {
        return messages.size
    }
}

Ответы (0 шт):