如何使函数等待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
相关产品推荐
相关产品推荐

