ArrayList заполняет не правильно при разборе с Retrofit - PullRequest
0 голосов
/ 20 мая 2018

У меня есть массив модели "Event".Есть модель "Место", которая может быть нулевой.Итак, я пытаюсь проанализировать JSON с идентификатором места и, если он нулевой, добавить «нулевой» в ArrayList.В то время как я отлаживаю цикл for вручную, ArrayList корректен на выходе, но если я не отлаживаю цикл for, результат совсем не корректен.

Слева правильно.

Correct Incorrect

Фрагмент моего кода:

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 Ответ

0 голосов
/ 20 мая 2018

У вас есть два недостатка:

  1. Использовать non-threadsafe (List) контейнер без синхронизации
  2. Доступ к списку, в то время как ваш модифицированный поток может быть не возвращен.

Чтобы решить (1), я предлагаю вам использовать потокобезопасный контейнер, такой как Vector, после чего вы можете преобразовать его в List после завершения.

Чтобы решить (2), вы можетеиспользуйте Thread.join(), чтобы убедиться, что все вызовы API завершены, прежде чем переходить к следующему.

Еще одно замечание: вы не хотите вызывать Thread.join() в цикле for.Это заблокирует цикл.Вместо этого просто 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..
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...