Search code examples
androidrealmrx-java2android-jetpack-compose

Jetpack compose with RxJava2 and Realm


I am working my through a new android application using Jetpack Compose (1.0.0-alpha08) and RxJava2 to manage the flow of data from my model (Realm 10 in this case. For a given screen, I have a view model that defines the data that will be subscribed to by the top level Compostable view. So, for example:

ViewModel...

class ListItemViewModel: ViewModel() {
   val items: Flowable<Item>
       get() {
          val data1 = userRealm.where<Item1>()
             .also(query).findAllAsync().asFlowable()
             .onBackpressureLatest().doOnNext{System.out.println("Realm on Next")}
            .observeOn(
                Schedulers.single()
            ).filter{it.isLoaded}.map{ result ->
                System.out.println("Maping Realm")
                result
            }.doOnSubscribe {System.out.println("Subscribe")}
          val data2 == //same as above but with a different item

          return Flowable.combineLatest(data1, data2, combineFunction)
             .onBackpressureLatest()
             .doOnNext{System.out.println("Hello")}
             .doOnComplete {System.out.println("Complete")}
             .subscribeOn(AndroidSchedulers.mainThread())
       }
}

View

@Compostable
fun List(List<Item> items) {
   val viewModel: ListItemViewModel = viewModel()
   val list by viewModel.items.subscribeAsState(initial = listOf())
   ItemList(list = list)
}

@Compostable
fun ItemList(List<Item> items {
   LazyColumnFor(...) {
     .......
   }
}

Everything works as I would expect and the list renders on the screen as I want. However, what I assume would happen here is that the subscribe would only happen once and the Flowable would only push out new data as new data was emitted. As a result, I would only expect the various onNext methods to be triggered when new data was present in the stream, e.g. something changed in the realm db. As I am not adding/deleting any data to/from the Realm, once I have the first set of results, I would expect the flowable to go "silent".

However, when I run the above, the subscribe message related to the realm subscription is logged over and over. The same for the "Hello" and the other logging statements in the onNext methods. Also, if I add any logging in my combine function, I see those log statements in the same fashion as I see the "Hello" log. From this it seems like each time the List composable is being rendered, it resubscribes to the Flowable from my viewmodel and triggers the full process. As I said, I was expecting that this subscription would only happen once.

This is perhaps correct behaviour, but mentally, it feels like I am burning CPU cycles for no reason as my methods are being called over and over when no data has change. Am I setting things up correctly, or is there something flawed in how I have configured things?


Solution

  • I ultimately worked around the problem and took a hybrid approach where I used Realm/RXJava to handle the data flow and when things have changed, update a LiveData object.

    View Model

    private val internalItemList = MutableLiveData(listOf<Item>())
    val itemList: LiveData<List<Item>> = internalItemList
    
    //capture the subscription so you can dispose in onCleared()
    val subscription = items.observeOn(AndroidSchedulers.mainThread()).subscribe {
        this.internalItemList.value = it
    }
    

    View

    val list by viewModel.itemList.observeAsState(listOf())
    

    This is must less chatty and works as I want it to. Not sure if it is the correct way to do this, but it seems to be working