1

I'm quite new to RxJava and have a problem with customizing my flow. The use case here is:

The View

I have a RecyclerView with a GridLayoutManager that displays a grid of images and a footer with a TextView that will display the total amount of images. To put it into a context, me as a user can have a total of 15 images, reflected by the TextView which will say "15 images", but the grid will still show only 4 (understand it as a "preview"). Now, to show these images, in onComplete() of the Observable that I create, I will call adapter.notifyDatasetChanged(). However, its pointless to wait for these images to appear, if the list consists of, lets say, 200 images. I would like to notify the adapter as soon as 4 images are emitted from the list. My observable is created in that way:

Observable.just(user.getUserId())
            .subscribeOn(Schedulers.io())
            .map(this::getImageList)
            .flatMap(images -> Observable.fromIterable(images)
                .map(image -> image))
            .observeOn(AndroidSchedulers.mainThread());

Having done so, I can't notify the adapter in Observer.onNext(), because if the images.size == 200 then it will be notified 200 times (hope I'm correct here). I can't do it in Observer.onComplete() neither as it will wait for all of the 200 exemplary images to be emitted before the adapter gets notified. How can I intercept that flow, do an action (notify the adapter) when 4 items from the list have been emitted, but continue emitting the rest, so I can show the proper footer text with the total images amount, without completing with only 4 images?

UPDATE - for purposes outside of the scope of this question, I need the full list of images after the observable completes. I want to display 4 of them, update the TextView with the total amount of images retrieved AND store the list of total images retrieved.

Austie
  • 67
  • 7

1 Answers1

2

If you modify the code in your flatMap, you can still access image list and get its size.

Observable.just(user.getUserId())
        .subscribeOn(Schedulers.io())
        .map(this::getImageList)
        .flatMap(images -> {
               // you can access images size here, update footer
               footer.setText(images.size() + " images");
               // pass full list of images to your view, i.e like this
               view.setImages(images);
               return Observable.fromIterable(images)
            })
            .take(4)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(image -> { 
                                // add image to grid 
                                },
                       error -> { 
                                // handle error
                                }
                       () ->    {
                                // four images were emitted, emission complete
                                adapter.notifyDatasetChanged();
                                });
canihazurcode
  • 252
  • 2
  • 9
  • Thanks for your answer. I need to modify my question - thing is I need that list of images for further processing, outside of the scope of this question. The footer text was an example of why I needed the full list, although I see that a very weak example. In reality, I still need that full list of images. – Austie Oct 30 '17 at 12:53
  • Do you need to perform an action on your list as a whole, like getting its size or passing the list to adapter or do you need to emit those 200 images? In the first case, you can just modify the block of code, where you can still have an access to your list (below first comment). In the second case, I will update my answer – canihazurcode Oct 30 '17 at 13:09
  • Ok so it looks like this. I have a screen that displays a user profile. Based on the `userId`, I will get the user's list of images. However, not to stuff everything in the user profile, I want to show only 4 of them, with a footer that shows a text indicating how many images the user has in total. The footer is clickable, which opens a new screen showing the list of all of the images. This is why I need the full list of images, to pass it to the new screen which will display it, but only show 4 of them in the "mainscreen". Does it explain the situation better? – Austie Oct 30 '17 at 13:31
  • I think code in this answer is correct. @Austie, if you want to subscribe to one call multiple times, you would need a `ConnectableObservable`. See [this answer, it may help](https://stackoverflow.com/questions/35951942/single-observable-with-multiple-subscribers/35952390#35952390) – M. Prokhorov Oct 30 '17 at 13:34
  • It won't fix the issue I have. By calling `take(4)` after the flatmap, the observable will complete after the 4th image gets emitted. In the example of having 200 images, I want to get 4 images out of 200 emitted, notify the adapter, and complete the observable when it finishes emitting the 200 images that I will then add to the list. – Austie Oct 30 '17 at 13:40
  • @Austie I updated my answer. You can pass full list of images to your view or perform any action on the list in modified block of code – canihazurcode Oct 30 '17 at 13:51
  • Your updated answer helped me to get what I needed. Instead of calling `View.setImages(images);` I took my `ArrayList` and executed `ImageList.addAll(images)`. I will accept your answer since its what helped me get what I needed. Thanks! – Austie Oct 30 '17 at 14:09