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

如何使函数等待HTTP请求返回响应后再返回处理结果

解决同步等待HTTP响应并返回映射对象的问题

你现在遇到的核心问题是:getEventWithID方法里的HTTP请求是异步执行的,方法会在请求还没拿到响应时就返回空的Event对象,而实际的属性赋值和数据库插入都是在回调里完成的,这就导致调用方fetchAdvertEvent拿到的是未初始化的对象。

要实现"等待响应完成后再返回映射好的Event",可以用CountDownLatch来阻塞当前线程,直到异步回调执行完毕。下面是修改后的getEventWithID实现:

public static Event getEventWithID(Long eventID) throws InterruptedException {
    // 用CountDownLatch来等待异步回调完成,初始计数为1
    CountDownLatch latch = new CountDownLatch(1);
    final Event[] resultEvent = new Event[1]; // 用数组来在回调中修改外部变量
    final Throwable[] error = new Throwable[1]; // 捕获请求过程中的错误

    Map<String, Object> params = new HashMap<>();
    params.put("eventID", eventID);

    HttpHelper.getInstance().makeApiHttpRequestNewServer("get-event", params, new IHelperRequestCompletion<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            try {
                Event event = new Event();
                event.setID(response.getLong("uniqueID"));
                event.setPlaceID(response.getLong("placeID"));
                event.setType(response.getString("type"));
                event.setTimestamp(response.getDouble("date"));
                
                // 改用has判断是否存在key,比解析字符串更可靠
                if(response.has("people")){ 
                    JSONArray attendingPPL = response.getJSONArray("people");
                    Set<Long> attendingPPLList = new HashSet<>();
                    for (int i = 0; i < attendingPPL.length(); i++) {
                        attendingPPLList.add(attendingPPL.getLong(i)); // 直接获取Long类型,避免字符串解析报错
                    }
                    event.setAttendingPeopleIDs(attendingPPLList);
                }
                
                if(event.getID() != null) {
                    AppDatabase.getAppDatabase(BlocApplication.getAppContext()).eventDao().insertAll(event);
                }
                resultEvent[0] = event;
            } catch (Exception err) {
                Log.v("Error in getEventByID", err.getLocalizedMessage());
                error[0] = err;
            } finally {
                latch.countDown(); // 不管成功失败,都释放latch,解除线程阻塞
            }
        }

        @Override
        public void onError(Throwable throwable) {
            Log.v("Error in getEventByID", throwable.getLocalizedMessage());
            error[0] = throwable;
            latch.countDown();
        }
    });

    latch.await(); // 阻塞当前线程,直到latch计数归0

    // 处理错误情况,将异常抛给调用方处理
    if(error[0] != null) {
        throw new RuntimeException("Failed to fetch event data", error[0]);
    }

    return resultEvent[0];
}

然后调整调用方fetchAdvertEvent的逻辑:

public uk.co.createanet.bloc.Networking.DynamoDB.Mapping.Event fetchAdvertEvent(Long eventID) {
    try {
        return EventHelper.getEventWithID(eventID);
    } catch (InterruptedException e) {
        Log.v("fetchAdvertEvent", "Thread interrupted while fetching event", e);
        return null; // 也可以根据业务需求返回默认Event对象或抛出自定义异常
    }
}

关键细节说明:

  • CountDownLatch:相当于一个线程的"信号开关",初始计数为1,当异步回调执行完毕时调用countDown(),计数变为0,await()方法就会解除阻塞,继续执行后续代码。
  • 数组存储结果/错误:Java匿名内部类无法直接修改外部的非final变量,所以用数组来存储结果和错误信息,这样回调里可以修改数组内的元素。
  • 更可靠的JSON判断:替换response.toString().contains("people")为response.has("people"),避免JSON字符串格式变化导致的误判。
  • 错误传递:将请求过程中的异常捕获后,在主线程抛出,让调用方可以统一处理失败场景。

重要注意事项:

  • 绝对不要在**Android主线程(UI线程)**调用修改后的方法!await()会阻塞线程,导致UI卡顿甚至触发ANR(应用无响应)。建议在后台线程中调用,比如用ExecutorService、AsyncTask或者Kotlin协程(如果项目支持)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:34:27