处置后订阅可观察

时间:2017-05-15 10:22:01

标签: android rx-java

我在android repository by Fernando Cejas上构建我的应用程序,我在调用dispose后订阅observable时遇到问题。

当我来到仪表板时,我调用方法subscribeOnUserMessages.execute(new Subscriber(), new Params(token)),这是UseCase类中的方法

public void execute(DisposableObserver<T> observer, Params params) {
    Preconditions.checkNotNull(observer);
    final Observable<T> observable = this.buildUseCaseObservable(params)
            .subscribeOn(Schedulers.from(threadExecutor))
            .observeOn(postExecutionThread.getScheduler());
    addDisposable(observable.subscribeWith(observer));
}

在子类SubscribeOnUserMessages中,我只是像这样调用存储库 return messageRepository.subscribeOnUserMessages(params);

在我的socket实现中,我创建了这样的

return Observable.create(emitter -> {

        if (!isThereInternetConnection()) {
            Timber.w("Network connection exception");
            emitter.onError(new NetworkConnectionException());
            return;
        }

        /*
         * Open socket if not opened
         */
        openSocket(params.getToken());



        String channelName = CHANNEL_PRIVATE_USER + params.getAuthenticated().getUuid();

        if (subscribedChannels.contains(channelName)) {
            Timber.d("Channel %s is already subscribed", channelName);
            return;
        }


        JSONObject auth;

        try {
            auth = createAuthJson(CHANNEL, channelName, params.getToken());
        } catch (JSONException e) {
            Timber.e("Couldn't create auth json");
            emitter.onError(e);
            return;
        }

        mSocket.emit(SUBSCRIBE, auth);
        Timber.d("Emitted subscribe with channel: %s ", CHANNEL_PRIVATE_USER + params.getAuthenticated().getUuid());
        subscribedChannels.add(CHANNEL_PRIVATE_USER + params.getAuthenticated().getUuid());
        Timber.d("Subscribing on event: %s\n with user: %s", EVENT_USER_NEW_MESSAGE, params.getAuthenticated().getUuid());

        if (mSocket.hasListeners(EVENT_USER_NEW_MESSAGE)) {
            Timber.v("Socket already has listener on event: %s", EVENT_USER_NEW_MESSAGE);
            return;
        }


        mSocket.on(EVENT_USER_NEW_MESSAGE, args -> {
            if (args[1] == null) {
                emitter.onError(new EmptyResponseException());
            }

            Timber.d("Event - %s %s", EVENT_USER_NEW_MESSAGE, args[1].toString());

            try {
                MessageEntity messageEntity = messageEntityJsonMapper.transform(args[1]);
                emitter.onNext(messageEntity);
            } catch (JSONException e) {
                Timber.e(e, "Could not parse message json");
                emitter.onError(e);
            }
        });

    });

症状是我第一次订阅所有内容都会进入表示层。当我在进入第二个屏幕并且回来之后处理我只看到日志来到套接字实现,但没有经历。

我的问题是:是否有方法再次订阅同一个观察者?我已经尝试在单例中保存我的用例中的observable并订阅那个observable,没有帮助。

1 个答案:

答案 0 :(得分:0)

如果没有额外的信息和细节重新定位套接字实现,很难完全发现问题,但是,从你发布的代码中,你没有处置逻辑,所以你可以正确地调用dispose()来在正确的生命周期事件中Observable,您的套接字实际上将保持打开状态,并且可能无法正常断开/关闭。
这可能会导致在第二次打开并连接到套接字时出现问题,因为您可能会尝试重新打开已打开的套接字并依赖于可能存在问题的内部套接字impl。
(我可以在注释中看到openSocket如果还没有打开,但是在其他地方多次调用套接字上的某些方法或设置监听器时可能还有问题,再次取决于套接字impl)

作为一般指导原则,您应该使用emitter.setCancellable() / emitter.setDisposable()添加dispose逻辑,以便在不再需要时正确处理套接字资源,从而 - 再次应用subscribe时(无论是否相同)对象与否)将再次调用您的订阅逻辑,重新打开套接字并收听它。

我不清楚你是否想在移动到不同的屏幕时保持套接字打开(我认为这不是一个好习惯,因为你会保持这个资源的开放,可能永远不会回到屏幕再次使用它),但如果是@Phoenix Wang提到的情况,你可以使用发布类型运算符来组播Observable,这样每个新的Subscriber都不会尝试重新打开套接字(即调用订阅逻辑)但只会收到有关已经打开的套接字中运行的消息的通知。