RxJava:将observable拆分为两个列表

时间:2016-12-02 14:52:53

标签: rx-java rx-android rx-java2

USECASE: 我必须更新存储在本地数据库中的当前订单。步骤是:

  1. 从后端下载数据(~800项)
  2. 检查本地数据库是否已包含项目。后端人员使用字符串作为主键。
  3. 如果该项目不在数据库中,请添加它。
  4. 如果该项目在数据库中,请进行更新。
  5. 我的第一个解决方案有点容易。只需调用后端,为每个项目创建两个数据库查询。首先检查它是否已经存在,然后再添加或更新它。

    你可能想象它很慢。每次更新大约需要17.5秒。

    第二个解决方案:将数据库数据缓存到列表中,而不是每次在ArrayList中搜索时查询数据库。这导致更新时间降至16.5秒。我使用defer从数据库调用创建了Observable,并使用combineLatest来获取结果。

    当前解决方案: 瓶颈当然是数据更新。我正在使用的orm库启用批量更新。所以我必须创建两个列表: 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;
    }
    

    问题

    您是否知道如何以反应方式解决这个问题?是否有一个运算符允许将两个列表中的observable分开。或者也许我应该使用一个全局变量(似乎是一个坏主意)来保留要插入的数据和要更新的数据?

1 个答案:

答案 0 :(得分:1)

使用@Override public void start(Stage primaryStage) { Label label = new Label("Hello World!"); label.setTextFill(Color.WHITE); Pane content = new Pane(label); content.setPrefSize(2000, 2000); content.setBackground(new Background(new BackgroundFill( new LinearGradient(0, 0, 1, 1, true, CycleMethod.NO_CYCLE, new Stop(0, Color.RED), new Stop(1, Color.BLUE)), CornerRadii.EMPTY, Insets.EMPTY))); ScrollPane scrollPane = new ScrollPane(content); double targetX = 10; double targetY = 10; InvalidationListener listener = o -> { Bounds viewportBounds = scrollPane.getViewportBounds(); Bounds contentBounds = content.getBoundsInLocal(); Bounds labelBounds = label.getBoundsInLocal(); double factorX = Math.max(contentBounds.getWidth() - viewportBounds.getWidth(), 0); double factorY = Math.max(contentBounds.getHeight() - viewportBounds.getHeight(), 0); label.setTranslateX(targetX + scrollPane.getHvalue() * factorX - labelBounds.getMinX()); label.setTranslateY(targetY + scrollPane.getVvalue() * factorY - labelBounds.getMinY()); }; scrollPane.viewportBoundsProperty().addListener(listener); scrollPane.hvalueProperty().addListener(listener); scrollPane.vvalueProperty().addListener(listener); label.boundsInLocalProperty().addListener(listener); Scene scene = new Scene(scrollPane, 200, 200); primaryStage.setScene(scene); primaryStage.show(); listener.invalidated(null); } ,其中关键是它是否是更新/插入操作;你会得到一个包含密钥的GroupedObservable。使用该键执行适当的操作。