Retrofit - как сделать синхронный запрос внутри асинхронного запроса


Я реализую двухуровневый вложенный recyclerView, и оба вида recycler делают вызов API с помощью retrofit. Это метод, который делает синхронный запрос:

public void loadSectionStories(String sessionKey, CuratedSection section) {
    Call<JsonArray> subCall;
    subCall = TravelersApi.endpoint().getCuratedSectionTopics(sessionKey, section.id);

    try {
        Response<JsonArray> response = subCall.execute();
        if(response.code() != 200) {
            Toast.makeText(getApplicationContext(), "Cannot load page as of the moment.", Toast.LENGTH_SHORT).show();
            return;
        }
        JsonArray rawStories = response.body();
        if(rawStories.size() == 0) {
            //TODO: show placeholder
            return;
        }
        ArrayList<CuratedSectionItem> stories = new ArrayList<>();
        for(int i = 0; i < rawStories.size(); i++) {
            JsonObject jStories = rawStories.get(i).getAsJsonObject();
            JSONObject temp = new JSONObject(jStories.toString());
            JsonObject author = jStories.get("author").getAsJsonObject();
            CuratedSectionItem story = new CuratedSectionItem();
            story.title = jStories.get("title").getAsString();
            story.avatar = author.get("profile_photo").getAsString();
            story.displayPhoto = temp.getString("primary_photo");
            story.username = author.get("username").getAsString();
            story.description = jStories.get("content").getAsString();
            story.topicId = jStories.get("id").getAsString();
            story.postId = jStories.get("first_post_id").getAsString();
            story.hasReacted = false;
            story.upvotes = jStories.get("stats").getAsJsonObject().get("upvotes").getAsInt();
            stories.add(story);
        }
        section.stories = stories;
    } catch (IOException e) {
        Log.d("ERROR!", e.toString());
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

Это метод, который делает асинхронный запрос, а также вызывает loadSectionStories в потоке:

public void loadCuratedSections(final int start, final int limit) {
    SharedPreferences prefs = getSharedPreferences("user_session", MODE_PRIVATE);
    final String sessionKey = prefs.getString("session_key", null);

    Call<JsonArray> call;
    call = TravelersApi.endpoint().getCuratedSections(sessionKey);

    call.enqueue(new Callback<JsonArray>() {
        @Override
        public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
            if(response.code() != 200) {
                Toast.makeText(getApplicationContext(), "Cannot load page as of the moment.", Toast.LENGTH_SHORT).show();
                return;
            }
            JsonArray rawSections = response.body();
            if(rawSections.size() == 0) {
                return;
            }
            for (int i = start; i < limit; i++) {
                JsonObject jSection = rawSections.get(i).getAsJsonObject();
                final CuratedSection section = new CuratedSection();
                section.id = jSection.get("id").getAsString();
                section.header = jSection.get("section_header").getAsString();
                section.isShown = jSection.get("is_shown").getAsBoolean();

                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        loadSectionStories(sessionKey, section);
                    }
                });
                thread.start();
                curatedSections.add(section);
            }

        }

        @Override
        public void onFailure(Call<JsonArray> call, Throwable t) {
            Log.d("ERROR!", t.toString());
            t.printStackTrace();
        }
    });
}

Все работает нормально, за исключением того, что section.stories возвращает null. Это не имеет смысла для меня из-за этого утверждения section.stories = stories внутри loadSectionStories.

2 2

2 ответа:

Если вы используете раздел.истории, прежде чем ваш синхронный запрос будет завершен (который выполняется в новых потоках), то он вернет null, который в настоящее время происходит.

Так что либо вам придется удалить новый поток потоков, если вы хотите использовать его после завершения первого асинхронного запроса,

Или вы должны перезагрузить свой вид recycler, когда Вы истории обновляется.

Также почему вы выполняете синхронный запрос (loadSectionStories) в новом потоке, не так ли похоже на асинхронный запрос?

Retrofit asyncRetrofit = new Retrofit.Builder()
                    .baseUrl(URLS.MAIN_SERVER_URL)
                    // below line create thread for syncrouns request
                    .callbackExecutor(Executors.newSingleThreadExecutor())
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(httpClient.build())
                    .build();

Это запустит ваш запрос в asyncronous