RxJava Operator for switching method

时间:2017-08-05 11:34:46

标签: android kotlin rx-java rx-android

Im new with Rxjava on Android Project, here my code

class RadioListRepositoryImpl(private val apiServices: ApiServices, private val chlDao: ChannelDao) : RadioListRepository {

private val results: MutableList<DataResponse>

init {
    results = ArrayList<DataResponse>()
}

override fun getData(): Observable<DataResponse> {
    return dataFromMemory().switchIfEmpty(dataFromNetwork())
}

override fun dataFromMemory(): Observable<DataResponse> {

    val cacheDateExp = DateTime().minusHours(6)

    if(chlDao.isCacheExpired(cacheDateExp).isNotEmpty()){

        Logger.d("Get data from cache SQLITE")

        val chList: MutableList<DataResponse> = ArrayList()

        val cache = chlDao.loadAll()
        repeat(cache.size){ i ->
            val ch = DataResponse()
            ch.channelId = cache[i].channelId
            ch.channelTitle = cache[i].title

            chList.add(ch)
        }

        return Observable.from(chList)
    }else{
        chlDao.deleteAll()

        return Observable.empty<DataResponse>()
    }
}

override fun dataFromNetwork(): Observable<DataResponse> {
    val dttime = DateTime()
    return apiServices.getChannelList()
            .concatMap {
                dataListResponseModel -> Observable.from(dataListResponseModel.radio)
            }
            .doOnNext {
                channelDataResponse -> results.add(channelDataResponse)
            }
            .doOnNext { channelDataResponse ->
                Logger.d("Put data to cache")
                val c: ChannelEntitiy = ChannelEntitiy()
                c.channelId = channelDataResponse.channelId
                c.title = channelDataResponse.channelTitle
                chlDao.insert(c)
            }
}

}

My other class access method getData() and I want if data is empty from memory (sqlite) then get data from network.

But what I want is if data is empty from memory then get data from network insert to memory and after that getData() method return dataFromMemory()

Can I handle it using another Rx operator to simplify my code ?

1 个答案:

答案 0 :(得分:1)

When you want to get data from multi-sources, concat and first should suit for you.

// Our sources (left as an exercise for the reader)
Observable<Data> memory = ...;  
Observable<Data> disk = ...;  
Observable<Data> network = ...;

// Retrieve the first source with data
Observable<Data> source = Observable  
  .concat(memory, disk, network)
  .first();

concat() takes multiple Observables and concatenates their sequences. first() emits only the first item from a sequence. Therefore, if you use concat().first(), it retrieves the first item emitted by multiple sources.

The key to this pattern is that concat() only subscribes to each child Observable when it needs to. There's no unnecessary querying of slower sources if data is cached, since first() will stop the sequence early. In other words, if memory returns a result, then we won't bother going to disk or network. Conversely, if neither memory nor disk have data, it'll make a new network request.

Note that the order of the source Observables in concat() matters, since it's checking them one-by-one.

Then if you want to save data for each sources, just change a little bit it your source with doOnNext()

Observable<Data> networkWithSave = network.doOnNext(data -> {  
  saveToDisk(data);
  cacheInMemory(data);
});

Observable<Data> diskWithCache = disk.doOnNext(data -> {  
  cacheInMemory(data);
});