}I want the subscriber of the stream to receive updates of the database as soon as some change happ" name="description" /> }I want the subscriber of the stream to receive updates of the database as soon as some change happ" />
58111

Room with Flowable: initialize database if it's empty

Question:

I have following @Dao, that provides Flowable<User> stream:

@Dao interface UsersDao { @Query("SELECT * FROM users") fun loadUsers(): Flowable<List<User>> }

I want the subscriber of the stream to receive updates of the database as soon as some change happens there. Subscribing to Room's Flowable I will get that feature out of the box.

What I want is following: if database is empty I want to perform a web request and save users into database. The subscriber will automatically receive new updates that had just happened.

Now I want the client of the repository not to be aware all of the initialization logics: all he does - he performs usersRepository.loadUsers(). And all of these magic should take place inside the repository class:

class UsersRepository @Inject constructor( private val api: Api, private val db: UsersDao ) { fun loadUsers(): Flowable<List<User>> { ... } }

Of course I can use following approach:

fun loadUsers(): Flowable<List<User>> { return db.loadTables() .doOnSubscribe { if (db.getCount() == 0) { val list = api.getTables().blockingGet() db.insert(list) } } }

But I would like to construct the stream without using side-effects (doOn... operators). I've tried <a href="http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html#compose-io.reactivex.FlowableTransformer-" rel="nofollow">composing()</a> but that didn't help much. Been stuck on this for a while.

Answer1:

You could apply some conditional flatMaps:

@Dao interface UsersDao { @Query("SELECT * FROM users") fun loadUsers(): Flowable<List<User>> @Query("SELECT COUNT(1) FROM users") fun userCount() : Flowable<List<Integer>> @Insert // I don't know Room btw. fun insertUsers(List<User> users) : Flowable<Object> } interface RemoteUsers { fun getUsers() : Flowable<List<User>> } fun getUsers() : Flowable<List<User>> { return db.userCount() .take(1) .flatMap({ counts -> if (counts.isEmpty() || counts.get(0) == 0) { return remote.getUsers() .flatMap({ users -> db.insertUsers(users) }) .ignoreElements() .andThen(db.loadUsers()) } return db.loadUsers() }) }

Disclaimer: I don't know Room so please adapt the example above as the features of it allow.

Answer2:

Assuming your insert() call is async and also handles updates, you could do something like this:

fun loadUsers(): Flowable<List<User>> = userDao.getAllUsers().switchIfEmpty { api.getAllUsers().doOnNext { userDao.insert(it) } }

You could also use some:

fun loadUsers(): Flowable<List<User>> = userDao.getAllUsers().flatMap { it-> if (it.isEmpty()) api.getAllUsers().doOnNext { userDao.insert(it) } else Flowable.just(it)}

Advice:

You should consider the case when the data is stale, therefore you need to go another way around, do a network request and database call at the same time. Whichever observable finish first, take the result and display it. Updating database should be right after network call is done.

Recommend

  • Difference between Haskell and Idris: Reflection of Runtime/Compiletime in the type universes
  • unexpected behaviour following changing entity relationships
  • Combinations of elements of multiple arrays
  • POJOs populated by Hibernate are entities, business objects or data transfer objects?
  • Background location update every n minutes
  • Lvalue to rvalue conversion not performed
  • Reference to a vector still prints as a vector?
  • How to remove special characters in file names?
  • JProgressBar text overflow
  • jQuery UI .sortable() call is slow when applies to thousands of elements
  • IE8 stops network access after 5 long polling request
  • PE file - what's missing?
  • cURL for Windows can't make a secure connection to the Stack API
  • Why is new Number(8) not exactly equal to 8?
  • Passing a Scala type to a function
  • How can I stop my python script when another python script is running?
  • Pass nested C++ vector as built-in style multi-dimensional array
  • How to set the navigation bar to the top in Table View?
  • Ruby: FileUtils.cp truncates file; FileUtils.mv it does not?
  • goJS dropdown remove items
  • Initialization section of the package
  • Jquery UI Sortable, move item automatically
  • Angular page doesn't refresh after data is added or removed
  • MRO with multiple inheritance in python
  • How does the HEXTORAW() function work? What is the algorithm?
  • to implement a spinner in angular2+
  • What is the undocumented SessionIdInterface in PHP 5.5?
  • File extension of zlib zipped html page?
  • Failed to find version-tag string. File must be updated
  • Alamofire and Reachability.swift not working on xCode8-beta5
  • What does 'Language neutral' mean with regard to MAKELANGID?
  • Excel's Macro-Recorder usage
  • How to use carriage return with multiple line?
  • swift auto completion not working in Xcode6-Beta
  • Excel - Autoshape get it's name from cell (value)
  • WinForms: two way TextBox problem
  • Weird JavaScript statement, what does it mean?
  • ORA-29908: missing primary invocation for ancillary operator
  • how does django model after text[] in postgresql [duplicate]
  • need help with bizarre java.net.HttpURLConnection behavior