简体   繁体   中英

RxSwift track multiple observables activity

I have following code:

let categoriesRequest = APIService.MappableRequest(Category.self, resource: .categories)
let categoriesRequestResult = api.subscribeArrayRequest(categoriesRequest, from: actionRequest, disposedBy: disposeBag)

let newCategories = categoriesRequestResult
    .map { $0.element }
    .filterNil()

let categoriesUpdateData = DatabaseService.UpdateData(newObjectsObservable: newCategories)
let categoriesDatabaseResult = database.subscribeUpdates(from: categoriesUpdateData, disposedBy: disposeBag)

let latestTopicsRequest = APIService.MappableRequest(Topic.self, resource: .latestTopics)
let latestTopicsRequestResult = api.subscribeArrayRequest(latestTopicsRequest, from: actionRequest, disposedBy: disposeBag)

let newLastTopics = latestTopicsRequestResult
    .map { $0.element }
    .filterNil()

let latestTopicsUpdateData = DatabaseService.UpdateData(newObjectsObservable: newLastTopics)
let latestTopicsDatabaseResult = database.subscribeUpdates(from: latestTopicsUpdateData, disposedBy: disposeBag)

There are two requests that starts from the same publish subject actionRequest , and two database updates after these requests.

I need something like isActive , bool value which will return true if any of api/database task is in progress. Is it possible? I saw ActivityIndicator in RxSwift examples, but I don't know is it possible to use it in my case.

Code from api/database if needed:

// API
func subscribeArrayRequest<T>(_ request: MappableRequest<T>,
                              from triggerObservable: Observable<Void>,
                              disposedBy disposeBag: DisposeBag) -> Observable<Event<[T]>> {
    let result = ReplaySubject<Event<[T]>>.create(bufferSize: 1)

    triggerObservable
        .flatMapLatest {
            SessionManager
                .jsonArrayObservable(with: request.urlRequest, isSecured: request.isSecured)
                .mapResponse(on: APIService.mappingSheduler) { Mapper<T>().mapArray(JSONArray: $0) }
                .materialize()
        }
        .subscribe(onNext: { [weak result] event in
            result?.onNext(event)
        })
        .disposed(by: disposeBag)

    return result
}

// Database
func subscribeUpdates<N, P>(from data: UpdateData<N, P>, disposedBy disposeBag: DisposeBag) -> Observable<Void> {
    let result = PublishSubject<Void>()

    data.newObjectsObservable
        .observeOn(DatabaseService.writingSheduler)
        .subscribe(onNext: { [weak result] newObjects in
            // update db

            DispatchQueue.main.async {
                result?.onNext(())
            }
        })
        .disposed(by: disposeBag)

    return result
}

Thanks.

Found following solution: pass ActivityIndicator instance to services methods and use it like this:

func bindArrayRequest<T>(_ request: MappableRequest<T>,
                        from triggerObservable: Observable<Void>,
                        trackedBy indicator: RxActivityIndicator,
                        disposedBy disposeBag: DisposeBag) -> Observable<Event<[T]>> {
    let result = ReplaySubject<Event<[T]>>.create(bufferSize: 1)

    triggerObservable
        .flatMapLatest {
            SessionManager
                .jsonArrayObservable(with: request.urlRequest, isSecured: request.isSecured)
                .mapResponse(on: APIService.mappingSheduler) { Mapper<T>().mapArray(JSONArray: $0) }
                .materialize()
                .trackActivity(indicator)
        }
        .bind(to: result)
        .disposed(by: disposeBag)

    return result
}

Also wrap database update logic into observable and use it with .trackActivity(indicator) into flatMapLatest like in api.

Then use api/database methods like this:

let indicator = RxActivityIndicator()
isUpdatingData = indicator.asObservable() // needed bool observable

let categoriesRequest = APIService.MappableRequest(Category.self, resource: .categories)

let categoriesRequestResult = 
    api.bindArrayRequest(categoriesRequest, 
                         from: actionRequest,
                         trackedBy: indicator,
                         disposedBy: disposeBag)

let newCategories = categoriesRequestResult
    .map { $0.element }
    .filterNil()

let categoriesUpdateData = DatabaseService.UpdateData(newObjectsObservable: newCategories)

let categoriesDatabaseResult =
    database.bindUpdates(from: categoriesUpdateData,
                         trackedBy: indicator,
                         disposedBy: disposeBag)

let latestTopicsRequest = APIService.MappableRequest(Topic.self, resource: .latestTopics)

let latestTopicsRequestResult =
    api.bindArrayRequest(latestTopicsRequest,
                         from: actionRequest,
                         trackedBy: indicator,
                         disposedBy: disposeBag)

let newLastTopics = latestTopicsRequestResult
    .map { $0.element }
    .filterNil()

let latestTopicsUpdateData = DatabaseService.UpdateData(newObjectsObservable: newLastTopics)

let latestTopicsDatabaseResult = 
    database.bindUpdates(from: latestTopicsUpdateData,
                         trackedBy: indicator,
                         disposedBy: disposeBag)

isUpdatingData observable is what I needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM