You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java异步与Observable新手求助:如何确保异步执行完成后再继续?

解决Java Observable异步操作后的后续执行问题

嘿,刚接触Java异步编程和Observable确实容易踩这类坑——用Thread.sleep(100)来等待异步结果完全是碰运气,一旦网络延迟或者处理耗时超过100ms,你就拿不到想要的数据了。咱们来一步步拆解问题,找到靠谱的解决方案。

问题根源

你的代码里,Observable.subscribe()的回调是在异步线程执行的,而execute()方法里的callbackContext.success()是在调用线程(比如主线程)直接执行的,两者的执行顺序是不确定的。你用Thread.sleep()只是强行延迟后续代码,但根本不能保证异步操作已经完成,这才会出现数据未就绪的问题。

方案一:把后续逻辑放到Observable的回调里(推荐)

这是最符合RxJava异步设计思想的做法——既然异步操作的结果只有在subscribe的onNext回调里才能拿到,那直接把callbackContext.success()放到这个回调里就行,完全不需要用全局的allInfo来中转数据。

修改后的代码如下:

private void getGroupAllInfo(CallbackContext callbackContext){
    Log.d("executing: ", "getGroupAllInfo1");
    Observable observable = GsscFactory.executeGetZwaveAllInfo(this.sock, MationPlugin.gatewayId, MationPlugin.account, MationPlugin.password);
    observable.subscribe(
        // 异步操作成功时触发
        t -> {
            System.out.print(t);
            // 直接在这里执行后续的成功回调
            callbackContext.success(t.toString());
        },
        // 别忘记处理错误情况!
        error -> {
            callbackContext.error(error.getMessage());
        }
    );
}

public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    this.getGroupAllInfo(callbackContext);
    // 这里不需要sleep和额外的success调用了
    return true;
}

这样做的好处是:只有当GsscFactory.executeGetZwaveAllInfo()的异步操作完成并返回结果时,才会触发callbackContext.success(),从根本上保证了数据的就绪性,也避免了线程阻塞。

方案二:阻塞式获取结果(仅适合后台线程)

如果你确实需要把数据存入allInfo再处理,可以用RxJava的阻塞式操作符(比如blockingSingle()),但要注意:这种方式会阻塞当前线程,绝对不能在主线程使用,否则会导致UI卡顿甚至ANR。

代码示例:

private String getGroupAllInfo() {
    Log.d("executing: ", "getGroupAllInfo1");
    try {
        // 阻塞当前线程,直到Observable返回结果
        Object result = GsscFactory.executeGetZwaveAllInfo(this.sock, MationPlugin.gatewayId, MationPlugin.account, MationPlugin.password)
                .blockingSingle();
        System.out.print(result);
        return result.toString();
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException("获取数据失败", e);
    }
}

public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    try {
        String data = this.getGroupAllInfo();
        MationPlugin.allInfo.put("data", data);
        callbackContext.success(data);
    } catch (RuntimeException e) {
        callbackContext.error(e.getMessage());
    }
    return true;
}

补充说明:为什么之前subscribe里赋值变量外部拿不到?

因为subscribe的回调是在独立的异步线程中执行的,当execute()方法里的Thread.sleep(100)结束时,异步回调可能还没执行,这时候allInfo里的data自然是空的。异步编程的核心就是不要等待,而是让后续逻辑依赖回调触发,这样才能保证时序的正确性。

内容的提问来源于stack exchange,提问作者zifan yan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 15:27:32