2016-12-02 6 views
1

Usecase: Мне нужно обновить текущие заказы, хранящиеся в локальной базе данных. Шаги:RxJava: Разделить на два списка

  1. Загрузка данных из внутреннего интерфейса (~ 800 наименований)
  2. Проверить, если локальная база данных уже содержит элемент. Бэкэнд-парни используют строку в качестве первичного ключа.
  3. Если товара нет в базе данных, добавьте его.
  4. Если элемент находится в базе данных, обновите его.

Моим первым решением было своеобразно легко. Просто вызовите бэкэнд и создайте два запроса к базе данных для каждого элемента. Сначала проверьте, есть ли он там, во-вторых, чтобы добавить или обновить его.

Как вы можете себе представить, это было медленно. Около 17,5 сек для каждого обновления.

Второе решение: Кэш данных базы данных в список и вместо запроса базы данных при каждом поиске в ArrayList. Это привело к сокращению времени обновления до 16,5 секунд. Я использовал defer для создания Observable из вызова базы данных и combineLatest для получения результатов.

Текущее решение: Узкое место было, конечно же, обновлением данных. Библиотека ормы, которую я использую, включает пакетные обновления. Поэтому мне нужно создать два списка: DataToUpdate и DataToInsert.

Текущее решение работает примерно через 5,3 сек. Я доволен временем, но недоволен нереактивным способом.

Observable<List<OrderDto>> getAllOrdersObservable = backendService.getAllOrders(); 

ordersDisposable = Observable.combineLatest(getStoredOrder(), getAllOrdersObservable, this::insertOrUpdateOrders) 
     .subscribeOn(Schedulers.io()) 
     .observeOn(AndroidSchedulers.mainThread()) 
     .doOnComplete(() -> { 
      Log.d(TAG, "Duration: " + (System.currentTimeMillis() - start) + " ms"); 
      showSyncButton(); 
      notifyListenersDataDownloaded(); 
     }) 
     .subscribe(); 


private Observable<List<Order>> getStoredOrder() { 
    return Observable.defer(() -> { 
     Log.d(TAG, "Started loading orders from database"); 
     Observable<List<Order>> just = Observable.just(orderDao.loadAll()); 
     Log.d(TAG, "Ended loading orders from database"); 
     return just; 
    }); 
} 

private List<Order> insertOrUpdateOrders(List<Order> orders, List<OrderDto> orderDtos) { 
    List<Order> ordersToInsert = new LinkedList<>(); 
    List<Order> ordersToUpdate = new LinkedList<>(); 

    for (OrderDto orderDto : orderDtos) { 
     Order order = getOrderByOrderNumber(orders, orderDto.getNumber()); 
     if (order != null) { 
      dtoToEntityTransformer.updateFields(orderDto, order); 
      ordersToUpdate.add(order); 
     } else { 
      order = dtoToEntityTransformer.transformToEntity(orderDto); 
      ordersToInsert.add(order); 
     } 
    } 

    orderDao.insertInTx(ordersToInsert); 
    orderDao.updateInTx(ordersToUpdate); 

    return orders; 
} 

Вопрос

Есть ли у вас представление о том, как решить эту проблему в реактивном способе? Есть ли оператор, который позволяет разделить наблюдаемые в двух списках. Или, может быть, я должен использовать глобальную переменную (похоже, плохую идею), чтобы сохранить информацию, которую данные вставлять и какие обновления?

ответ

1

Используйте groupBy, где ключ - это операция обновления/вставки; вы вернете GroupedObservable, который включает в себя ключ. Используйте эту клавишу для выполнения соответствующей операции.