-1

I am using a livedata on viewmodel and flow on repository and data source. when I tried to connect them to each other and get a data stream as below that error occurred

Error

java.lang.ClassCastException: androidx.lifecycle.CoroutineLiveData cannot be cast to com.versec.versecko.util.SingleLiveEvent

ViewModel

val singleChat : SingleLiveEvent<ChatRoomEntity> = repository.getChatRooms().asLiveData() as SingleLiveEvent<ChatRoomEntity>

Fragment

viewModel.singleChat.observe(viewLifecycleOwner, Observer {

        roomList.add(it)
        chatRoomAdapter.changeRooms(roomList)
        chatRoomAdapter.notifyDataSetChanged()
    })

SingleLiveEvent

class SingleLiveEvent<T> : MutableLiveData<T>() {

companion object {

    private val TAG = "SingleLiveEvent"
}

private val pending : AtomicBoolean = AtomicBoolean(false)


@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {


    if (hasActiveObservers()) { Log.w(TAG, "Multiple Observers ,,,")}

    super.observe(owner, Observer { t ->
        if (pending.compareAndSet(true, false)) {
            observer.onChanged(t)
        }
    })

}

@MainThread
override fun setValue(value: T?) {
    pending.set(true)
    super.setValue(value)
}

@MainThread
fun call() {value = null }       }

what is the proper way to use both??

Roman Svitukha
  • 1,302
  • 1
  • 12
  • 22
tring yuo
  • 67
  • 6
  • 1
    Can you explain why did you create a custom LiveData? What is the use of this `pending` property? – Arpit Shukla Sep 23 '22 at 06:28
  • [singleLiveEvent](https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150) check this bro – tring yuo Sep 23 '22 at 06:49
  • 1
    Maybe this [resource](https://github.com/alexmamo/FireApp) will help. – Alex Mamo Sep 23 '22 at 07:07
  • @tringyuo What does `repository.getChatRooms()` return? Does it return a single `ChatRoomEntity`? Can you share the corresponding Dao query? – Arpit Shukla Sep 23 '22 at 07:18
  • 1
    @AlexMamo omg. Alex! really thank you! this code will upgrade my android programming level absolutely!!! – tring yuo Sep 23 '22 at 08:25
  • @ArpitShukla it return Flowexactly. how about to read this [link](https://medium.com/androiddevelopers/migrating-from-livedata-to-kotlins-flow-379292f419fb) ? it maybe helpful to u :) – tring yuo Sep 23 '22 at 08:27
  • I have worked with Room. I want to understand why are you returning a single chat entity and then adding to your recycler view list. Why aren't you fetching all the chat rooms at once. Also, don't you think your function should be named `getChatRoom` instead of `getChatRooms` if it is returning just a single chat room. – Arpit Shukla Sep 23 '22 at 08:35
  • @ArpitShukla check this [question](https://stackoverflow.com/questions/73810218/how-to-avoid-first-callback-of-livedata-after-register-observer) and answer. that's why I named it as **getChatRoom** it could get all data and then updated data. and this is not Room but Firebase rdb haha – tring yuo Sep 23 '22 at 08:39
  • 2
    This is not what SingleLiveEvent is for. It's for events that should only be reacted to once from anywhere, not for data to display. It will lose the data if the screen rotates. And the reason it is crashing is that you're doing a cast that doesn't make sense. Casting does not convert one type to another. Conversion must be done manually. Casting only works when an instance *already is* the type you are casting to but that other type is not currently visible in scope. – Tenfour04 Sep 23 '22 at 15:01
  • @Tenfour04 so what kind of livedata or other thing is best for that task? – tring yuo Sep 24 '22 at 05:11
  • All you should need is a regular MutableLiveData. Someone already wrote an answer to you explaining it. – Tenfour04 Sep 24 '22 at 12:21
  • @Tenfour04 just regular MutableLiveData not helpful in my case. so I changed it with SharedFlow – tring yuo Sep 25 '22 at 05:01

1 Answers1

1

From what I understood, the reason you are using SingleLiveData is because you don't want the observer to receive same ChatRoomEntity twice in which case it will be duplicated in the list. A simple solution to this is to maintain the list inside the ViewModel and expose this list to the UI, then you won't have to use workarounds like SingleLiveData.

// ViewModel
private val _chatRoomsLiveData = MutableLiveData(emptyList<ChatRoomEntity>())
val chatRoomsLiveData: LiveData<List<ChatRoomEntity>> = _chatRoomsLiveData

init {
    viewModelScope.launch {
        repository.getChatRooms().collect {
            _chatRoomsLiveData.value = _chatRoomsLiveData.value!! + it
        }
    }
}

// Fragment
viewModel.chatRoomsLiveData.observe(viewLifecycleOwner, Observer {
    chatRoomAdapter.changeRooms(it)
    chatRoomAdapter.notifyDataSetChanged()
})
Arpit Shukla
  • 9,612
  • 1
  • 14
  • 40