使用 Retrofit 解析时 ArrayList 填充不正确

ArrayList fills not correctly while parsing with Retrofit

我有一个模型数组 "Event"。有一个模型 "Place" 可以为空。所以,我尝试用 place id 解析 JSON,如果它为 null,则将 "null" 添加到 ArrayList。当我手动调试 for 循环时,ArrayList 在输出中是正确的,但如果我不调试 for 循环,结果根本不正确。

左边是正确的。

我的代码片段:

private void handleResponse(ResponseData responseData) {

    ArrayList<Event> events = responseData.getEvents();
    PlaceApiService placeApiService = RetrofitClient.getPlaceApiService();
    int eventsSize = events.size();

    List<Thread> threads = new ArrayList<>();
    for (int i = 0; i < eventsSize; i++) {
        Place place = responseData.getEvents().get(i).getPlace();
        if (place != null) {
            Call<PlaceDetail> call = placeApiService.getPlaceJson(place.getId());

            Thread thread = new Thread(() -> {
                try {
                    Response<PlaceDetail> response = call.execute();
                    if (response.isSuccessful()) {
                        placeDetails.add(response.body());
                    } else {
                        Log.d("myLog", String.valueOf(response.message()));
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            thread.start();
            threads.add(thread);
        } else {
            placeDetails.add(null);
        }
    }

    for (Thread t : threads) {
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    ArrayList<PlaceDetail> details = new ArrayList<>(placeDetails);
    getViewState().showProgress(false);
    getViewState().finishSwipeRefresh();
    getViewState().showData(responseData.getEvents(), details);
}

你有两个缺点:

  1. 使用不同步的非线程安全 (List) 容器
  2. 在您的改装线程可能未返回时访问列表。

为了解决(1),我建议你使用像Vector这样的线程安全容器,然后你可以在完成后将它转换为List

要解决 (2),您可以使用 Thread.join() 确保所有 API 调用在下一步之前完成。

再补充一点,您不想在 for 循环中调用 Thread.join()。它会阻塞循环。相反,只是 start() 并将线程处理程序存储到数组,然后在 for 循环之后,循环遍历线程处理程序并调用 join():

List<Thread> threads = new ArrayList<>();
for (int i = 0; i < eventsSize; i++) {
    if (...) {
        Thread t = new Thread()...;
        t.start(); // Don't call join() after start() here
        threads.add(t);
    } else {
       ...
    }
}

// Instead call join here:

for (Thread t : threads) {
   t.join(); // Need try catch
}
.. bla bla..