如何用rxjava2取消Observable.timer?

时间:2017-05-30 22:52:52

标签: android rx-java reactive-programming retrofit2 rx-java2

我的代码中有一个重试机制,我使用下面的行来执行我的重试逻辑。例如,我生成一个随机的毫秒来延迟执行。当计时器滴答到30 * 1000毫秒时,我想取消此计时器。如何取消此计时器并立即执行我的逻辑。

var graph = d3.select('.graph')
    .append('svg')
    .attr('width', window.innerWidth)
    .attr('height', window.innerHeight);

var defs = graph.append('svg:defs');

var blueGradient = defs.append('svg:linearGradient')
    .attr('id', 'b')
    .attr('x1', 0)
    .attr('y1', 0)
    .attr('x2', 0)
    .attr('y2', 1)
    .attr('spreadMethod', 'pad');

blueGradient.append('svg:stop')
    .attr('offset', '0%')
    .attr('stop-color', '#e4f5fc')
    .attr('stop-opacity', 1);

blueGradient.append('svg:stop')
    .attr('offset', '100%')
    .attr('stop-color', '#2ab0ed')
    .attr('stop-opacity', 1);

var orangeGradient = defs.append('svg:linearGradient')
    .attr('id', 'o')
    .attr('x1', 0)
    .attr('y1', 0)
    .attr('x2', 0)
    .attr('y2', 1)
    .attr('spreadMethod', 'pad');

orangeGradient.append('svg:stop')
    .attr('offset', 0)
    .attr('stop-color', '#f6e6b4')
    .attr('stop-opacity', 1);

orangeGradient.append('svg:stop')
    .attr('offset', '100%')
    .attr('stop-color', '#ed9017')
    .attr('stop-opacity', 1);

var arrow = defs.append('svg:marker')
    .attr('id', 'arrow')
    .attr('orient', 'auto')
    .attr('markerWidth', 2)
    .attr('markerHeight', 4)
    .attr('refX', 0.1)
    .attr('refY', 2);

arrow.append('path')
    .attr('d', 'M0,0 V4 L2,2 Z')
    .attr('fill', '#aaa');

var line = d3.line()
    .x(function(d) { console.log(d); return d.x; })
    .y(function(d) { console.log(d); return d.y; });

var appended = false;
var step = -1;

document.addEventListener('keydown', drawGraph);
document.addEventListener('click', drawGraph);

drawGraph();

function drawGraph(event) {
    var nodes = [
        {
            x: 200,
            y: 50,
            c: 'b',
        },
        {
            x: 400,
            y: 50,
            c: 'b'
        },
        {
            x: 600,
            y: 50,
            c: 'b'
        },
        {
            x: 725,
            y: 175,
            c: 'b'
        },
        {
            x: 600,
            y: 300,
            c: 'o'
        },
        {
            x: 400,
            y: 300,
            c: 'o'
        },
        {
            x: 200,
            y: 300,
            c: 'o'
        },
        {
            x: 75,
            y: 175,
            c: 'o'
        }
    ];

    switch (step) {
        case -1:
            var paths;

            if (!appended) {
                paths = graph.selectAll('path.nodes')
                    .data(nodes)
                    .enter()
                    .append('path')
                    .attr('stroke', '#aaa')
                    .attr('stroke-width', 10)
                    .attr('fill', 'none')
                    .attr('marker-end', 'url(#arrow)');

                graph.selectAll('circle.nodes')
                    .data(nodes)
                    .enter()
                    .append('svg:circle')
                    .attr('cx', function(d) {
                        return d.x;
                    })
                    .attr('cy', function(d) {
                        return d.y;
                    })
                    .attr('r', 19)
                    .attr('fill', function(d) {
                        return 'url(#' + d.c + ')';
                    })
                    .attr('stroke', function(d) {
                        switch (d.c) {
                            case 'b':
                                return '#2E75B6';
                            case 'o':
                                return '#BF9000';
                        }
                    });
            } else {
                paths = graph.selectAll('path')
                    .transition();
            }

            paths.attr('d', function(currentNode, i) {
                if (!currentNode) {
                    return;
                }

                if (appended) {
                    // For some reason, the index is base 0 when the elements
                    // are appended, then 1 based afterwards.
                    i--;
                }

                currentNode = nodes[i];

                var nextNode = i < nodes.length - 1 ?
                    nodes[i + 1] :
                    nodes[0];

                startPath = {
                    x: currentNode.x,
                    y: currentNode.y,
                    c: currentNode.c
                };

                endPath = {
                    x: nextNode.x,
                    y: nextNode.y,
                    c: nextNode.c
                };

                return line([startPath, endPath]);
            });

            appended = true;
            step++;
            break;

        case 0:
            graph.selectAll('path')
                .transition()
                .attr('d', function(currentNode, i) {
                    if (!currentNode) {
                        return;
                    }

                    // For some reason, the index is suddenly base 1, not 0.
                    i--;

                    var nextNode = i < nodes.length - 1 ?
                        nodes[i + 1] :
                        nodes[0];

                    startPath = {
                        x: currentNode.x,
                        y: currentNode.y,
                        c: currentNode.c
                    };

                    endPath = {
                        x: nextNode.x,
                        y: nextNode.y,
                        c: nextNode.c
                    };
                    var diff = {
                        x: nextNode.x - currentNode.x,
                        y: nextNode.y - currentNode.y
                    };

                    var margins = {
                        current: {
                            x: 0,
                            y: 0
                        },
                        next: {
                            x: 0,
                            y: 0
                        }
                    };

                    if (diff.x > 0 && diff.y === 0) {
                        margins.current.x = 30;
                    } else if (diff.x < 0 && diff.y === 0) {
                        margins.current.x = -30;
                    } else if (diff.x > 0) {
                        margins.current.x = 20;
                    } else if (diff.x < 0) {
                        margins.current.x = -20;
                    }

                    if (diff.y > 0 && diff.x === 0) {
                        margins.current.y = 30;
                    } else if (diff.y < 0 && diff.x === 0) {
                        margins.current.y = -30;
                    } else if (diff.y > 0) {
                        margins.current.y = 20;
                    } else if (diff.y < 0) {
                        margins.current.y = -20;
                    }

                    if (margins.current.x != 0) {
                        margins.next.x = margins.current.x < 0 ?
                            Math.abs(margins.current.x * 1.5) :
                            margins.current.x * -1.5;
                    }

                    if (margins.current.y != 0) {
                        margins.next.y = margins.current.y < 0 ?
                            Math.abs(margins.current.y * 1.5) :
                            margins.current.y * -1.5;
                    }

                    startPath.x += margins.current.x;
                    startPath.y += margins.current.y;
                    endPath.x += margins.next.x;
                    endPath.y += margins.next.y;

                    return line([startPath, endPath]);
                });

            step--;
            break;
    }
}

提前致谢。

2 个答案:

答案 0 :(得分:1)

如果我正确理解了您的问题,您希望能够将多个条件组合到重试中,这意味着重试将在最多一定时间(定时器)之后发生,或者甚至在某个事件发生后更早(网络已连接) )。
在这种情况下,您需要合并这2个事件,首先,您需要一些handler-id来通知网络事件(它是一个不同的讨论如何创建它,不应该是一个问题使用Observable包装系统广播事件,然后你可以这样做:

Observable

网络状态private Observable<NetworkState> networkStateObservable; public class RetryWhenException implements Function<Observable<? extends Throwable>, Observable<?>> { public Observable<?> apply( final Observable<? extends Throwable> observable) throws Exception { return observable.zipWith(Observable.range(1, count + 1), Wrapper::new) .flatMap(wrapper -> { long delay = 60 * 1000; Observable<NetworkState> networkConnectedEvents = networkStateObservable.filter(networkState -> networkState.isConnected()) take(1); Observable<Long> timer = Observable.timer(delay, TimeUnit.MILLISECONDS); return Observable.amb(Arrays.asList(networkConnectedEvents, timer)); }); } } 已过滤,仅在连接时获得通知,Observable也是为了确保在我们第一次收到通知后将取消订阅(不再需要收听) )。
take(1)运算符似乎非常合适,因为它将选择将发出冷杉的amb(),并取消订阅另一个,这意味着如果网络Observable在计时器之前发出,计时器Observable将被取消订阅(=计时器将被取消)。

编辑:

删除了错误的takeUntil(networkConnectedEvents),不需要它,因为amb会在需要时取消订阅。

答案 1 :(得分:0)

非常感谢您的回复。这正是我所寻找的。我按照你的描述创建了一个网络Observable包装器, 似乎networkStateObservable在onNetworkChanged()被调用后没有发出(state.isConnected()为true)。 如何使networkStateObservable正确发出?非常感谢。 我在

中打了下面的行
e.onNext(state);  
 e.onComplete();

发出networkStateObservable是错误的吗?

Observable<NetworkState> networkStateObservable = getNetworkObservableWrapper();
public Observable<NetworkState> getNetworkObservableWrapper() {
        return Observable.create(new ObservableOnSubscribe<NetworkState>() {
            @Override
            public void subscribe(final ObservableEmitter<NetworkState> e) throws Exception {
                final NetworkChangedListener listener = new NetworkChangedListener() {
                    @Override
                    public void onNetworkChanged(NetworkState state) {
                        //Below lines were called, but Observable.amb(Arrays.asList(networkConnectedEvents, timer)); didn't work.                       
                        e.onNext(state);
                        e.onComplete();
                    }
                };
                registerNetworkChanged(listener);
            }
        });
    }