Страницы

Поиск по вопросам

пятница, 12 июля 2019 г.

Как правильно делать запросы в операторе flatMap?

Я получаю с сервера список чатов(переписок). Их запихиваю в класс ChatsModel. И в этом классе имеется userId, то есть в каждом чате имеется id того пользователя. Других информации о пользователе нет.И еще есть одно поле для данных о пользователе типа UserMessagesResponse
Так вот для начала этот userMessagesResponse равен null
После того как я получил список чатов и userId, я должен отправить другой запрос для получения информации о пользователе. Делаю я это таким образом:
private void loadChatsFromNetwork(int count, AccessDataModel accessDataModel) { String accessToken = accessDataModel.getAccessToken();
Flowable chatsModelSingle = getChatsApi().getChats(count, accessToken, Constants.api_version) .subscribeOn(Schedulers.io()) .flatMap(chatsModel -> { RealmList items = chatsModel.getResponse().getItems(); StringBuilder userIds = new StringBuilder();
for (Item item : items) { userIds.append(item.getMessage().getUserId()).append(","); }
return loadUsersById(userIds, chatsModel); }) .observeOn(AndroidSchedulers.mainThread());
chatsModelSingle.subscribe(chatsModel -> { Log.d(TAG, chatsModel.getResponse().getItems().first().getMessage().getMessagesUserItem().getFirstName()); chatsRepository.updateChatsData(chatsModel); iGetChatsCallback.onGetChatsSuccess(chatsModel); }, throwable -> { iGetChatsCallback.onGetChatsError(throwable.getMessage()); Log.d(TAG, "onError() " + throwable.getMessage()); }); }
private ChatsModel loadUsersById(StringBuilder userIds, ChatsModel chatsModel) {
MyApplication.getChatsApi().getUsersByChats(userIds.toString(), "photo_100") .subscribe(messagesUser -> {
RealmList item = chatsModel.getResponse().getItems();
for (int i = 0; i < item.size(); i++) { Message message = item.get(i).getMessage();
RealmList messagesUserItemList = messagesUser.getUserMessagesResponse(); for (UserMessagesResponse messagesResponse : messagesUserItemList) { if (messagesResponse.getUid().equals(message.getUserId())) { message.setMessagesUserItem(messagesResponse); chatsModel.getResponse().getItems().get(i).setMessage(message); } } }
});
return chatsModel; }
Все эти действия происходят в операторе flapMap, так как мне нужно полученную информацию о пользователе запихнуть в поле userMessagesResponse класса ChatsModel. И в случае успеха отправляю в adapter.
Оба запроса корректно работают. Получаю список userid, получаю данные о пользователе.
Проблема в том, после возвращения chatsModel в flatMap, где return chatsModel, дальше ничего не происходит, то есть до подписчика не доходит ничего, точнее подписчик никак не реагирует.
Вопрос: Как исправить это и вообще как правильно решать такого рода задачи?


Ответ

Если формально, то проблема ваша в том, что вы делаете return chatsModel до того момента, как выполнится код из subscribe, в котором он наполняется.
Если по сути, то ошибка у вас в идеологии. Вы пытаетесь скрестить ежа с ужом. Идеология ReactiveX состоит в том, что вы управляете не фиксированными объектами, а потоками данных(событий), причем асинхронно. А у вас получается так: пошел асинхронный поток, вы его тут-же пытаетесь собрать в объект, синхронно причем, и запустить в другой поток.
Распишем ваш поток:
Происходит какое-то событие, которое инициирует загрузку чатов Получаем список чатов List Для каждого чата получаем информацию о пользователе (getUserInfo) Делаем с этими чатами какую-то полезную работу (redrawMyNiceChatsTable)
Т.е. логика у вас должны быть примерно следующая(отчасти псевдокод):
class MyMainClass{ private ChatsUpdater updater = new ChatsUpdater(); private List chats = new ArrayList<>();
private void onSomeEventOccured(){ chats.clear(); updater.startUpdate() .subscribe( {chat -> chats.add(chat)}, // onNext {redrawMyNiceChatsTable(chats)} // onComplete ) } }
class ChatsUpdater{ public Flowable startUpdate(){ return getChats().flatMap( chat -> getUserInfo(chat), (chat, userInfo) -> { chat.setUserInfo(userInfo); return Observable.just(chat); } ) }
private Flowable getChats(){ ..... }
private Flowable getUserInfo(Chat chat){ ..... } }
UPD Ну а если совсем по уму, то, так как у вас жесткая, обязательная, цепочка Chat->UserInfo, вам надо переделать API на стороне сервера, чтобы оно отдавало сразу всю необходимую информацию.

Комментариев нет:

Отправить комментарий