PagingData

public final class PagingData<T extends Object>


Container for Paged data from a single generation of loads.

Each refresh of data (generally either pushed by local storage, or pulled from the network) will have a separate corresponding PagingData.

Summary

Public methods

static final @NonNull PagingData<@NonNull T>
<T extends Object> empty()

Create a PagingData that immediately displays an empty list of items when submitted to a presenter.

static final @NonNull PagingData<@NonNull T>
<T extends Object> empty(
    @NonNull LoadStates sourceLoadStates,
    LoadStates mediatorLoadStates
)

Create a PagingData that immediately displays an empty list of items when submitted to a presenter.

static final @NonNull PagingData<@NonNull T>
<T extends Object> from(@NonNull List<@NonNull T> data)

Create a PagingData that immediately displays a static list of items when submitted to a presenter.

static final @NonNull PagingData<@NonNull T>
<T extends Object> from(
    @NonNull List<@NonNull T> data,
    @NonNull LoadStates sourceLoadStates,
    LoadStates mediatorLoadStates
)

Create a PagingData that immediately displays a static list of items when submitted to a presenter.

Extension functions

final @NonNull PagingData<@NonNull T>
<T extends Object> PagingDataFutures.filterAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull T, @NonNull Boolean> predicate,
    @NonNull Executor executor
)

Returns a PagingData containing only elements matching the given predicate.

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingDataFutures.flatMapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull T, @NonNull Iterable<@NonNull R>> transform,
    @NonNull Executor executor
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

final @NonNull PagingData<@NonNull R>
<T extends R, R extends Object> PagingDataFutures.insertSeparatorsAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull AdjacentItems<@NonNull T>, R> generator,
    @NonNull Executor executor
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingDataFutures.mapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull T, @NonNull R> transform,
    @NonNull Executor executor
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.

final @NonNull PagingData<@NonNull T>
<T extends Object> PagingDataTransforms.filter(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Executor executor,
    @NonNull Function1<@NonNull T, @NonNull Boolean> predicate
)

Returns a PagingData containing only elements matching the given predicate.

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingDataTransforms.flatMap(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Executor executor,
    @NonNull Function1<@NonNull T, @NonNull Iterable<@NonNull R>> transform
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

final @NonNull PagingData<@NonNull T>
<T extends Object> PagingDataTransforms.insertFooterItem(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull TerminalSeparatorType terminalSeparatorType,
    @NonNull T item
)

Returns a PagingData containing each original element, with the passed footer item added to the end of the list.

final @NonNull PagingData<@NonNull T>
<T extends Object> PagingDataTransforms.insertHeaderItem(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull TerminalSeparatorType terminalSeparatorType,
    @NonNull T item
)

Returns a PagingData containing each original element, with the passed header item added to the start of the list.

final @NonNull PagingData<@NonNull R>
<R extends Object, T extends R> PagingDataTransforms.insertSeparators(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull TerminalSeparatorType terminalSeparatorType,
    @NonNull Executor executor,
    @NonNull Function2<T, T, R> generator
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingDataTransforms.map(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Executor executor,
    @NonNull Function1<@NonNull T, @NonNull R> transform
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.

final @NonNull PagingData<@NonNull T>
<T extends Object> PagingRx.filterAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Boolean>> predicate
)

Returns a PagingData containing only elements matching the given predicate.

final @NonNull PagingData<@NonNull T>
<T extends Object> PagingRx.filterAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Boolean>> predicate
)

Returns a PagingData containing only elements matching the given predicate.

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingRx.flatMapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Iterable<@NonNull R>>> transform
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingRx.flatMapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Iterable<@NonNull R>>> transform
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

final @NonNull PagingData<@NonNull R>
<T extends R, R extends Object> PagingRx.insertSeparatorsAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function2<T, T, @NonNull Maybe<@NonNull R>> generator
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

final @NonNull PagingData<@NonNull R>
<T extends R, R extends Object> PagingRx.insertSeparatorsAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function2<T, T, @NonNull Maybe<@NonNull R>> generator
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingRx.mapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull R>> transform
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.

final @NonNull PagingData<@NonNull R>
<T extends Object, R extends Object> PagingRx.mapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull R>> transform
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.

Public methods

empty

Added in 3.0.0
public static final @NonNull PagingData<@NonNull T> <T extends Object> empty()

Create a PagingData that immediately displays an empty list of items when submitted to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter and dispatches LoadState.NotLoading on all LoadStates to the presenter.

empty

Added in 3.2.0
public static final @NonNull PagingData<@NonNull T> <T extends Object> empty(
    @NonNull LoadStates sourceLoadStates,
    LoadStates mediatorLoadStates
)

Create a PagingData that immediately displays an empty list of items when submitted to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter.

Parameters
@NonNull LoadStates sourceLoadStates

LoadStates of PagingSource to pass forward to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter.

LoadStates mediatorLoadStates

LoadStates of RemoteMediator to pass forward to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter.

from

public static final @NonNull PagingData<@NonNull T> <T extends Object> from(@NonNull List<@NonNull T> data)

Create a PagingData that immediately displays a static list of items when submitted to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter and dispatches LoadState.NotLoading on all LoadStates to the presenter.

Parameters
@NonNull List<@NonNull T> data

Static list of T to display.

from

public static final @NonNull PagingData<@NonNull T> <T extends Object> from(
    @NonNull List<@NonNull T> data,
    @NonNull LoadStates sourceLoadStates,
    LoadStates mediatorLoadStates
)

Create a PagingData that immediately displays a static list of items when submitted to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter.

Parameters
@NonNull List<@NonNull T> data

Static list of T to display.

@NonNull LoadStates sourceLoadStates

LoadStates of PagingSource to pass forward to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter.

LoadStates mediatorLoadStates

LoadStates of RemoteMediator to pass forward to a presenter. E.g., androidx.paging.AsyncPagingDataAdapter.

Extension functions

PagingDataFutures.filterAsync

public final @NonNull PagingData<@NonNull T> <T extends Object> PagingDataFutures.filterAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull T, @NonNull Boolean> predicate,
    @NonNull Executor executor
)

Returns a PagingData containing only elements matching the given predicate.

Parameters
@NonNull AsyncFunction<@NonNull T, @NonNull Boolean> predicate

AsyncFunction returning false for unmatched items which should be filtered.

@NonNull Executor executor

Executor to run the AsyncFunction in.

PagingDataFutures.flatMapAsync

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingDataFutures.flatMapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull T, @NonNull Iterable<@NonNull R>> transform,
    @NonNull Executor executor
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

Parameters
@NonNull AsyncFunction<@NonNull T, @NonNull Iterable<@NonNull R>> transform

AsyncFunction to transform an item of type T a list of items of type R.

@NonNull Executor executor

Executor to run the AsyncFunction in.

PagingDataFutures.insertSeparatorsAsync

public final @NonNull PagingData<@NonNull R> <T extends R, R extends Object> PagingDataFutures.insertSeparatorsAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull AdjacentItems<@NonNull T>, R> generator,
    @NonNull Executor executor
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

Note that this transform is applied asynchronously, as pages are loaded. Potential separators between pages are only computed once both pages are loaded.

import androidx.paging.insertSeparatorsAsync
import androidx.paging.rxjava2.insertSeparatorsAsync

/*
 * Create letter separators in an alphabetically sorted list.
 *
 * For example, if the input is:
 *     "apple", "apricot", "banana", "carrot"
 *
 * The operator would output:
 *     "A", "apple", "apricot", "B", "banana", "C", "carrot"
 */
pagingDataStream.map { pagingData ->
    // map outer stream, so we can perform transformations on each paging generation
    pagingData.insertSeparatorsAsync(
        AsyncFunction<AdjacentItems<String>, String?> {
            Futures.submit(
                Callable<String?> {
                    val (before, after) = it!!
                    if (after != null && before?.first() != after.first()) {
                        // separator - after is first item that starts with its first letter
                        after.first().uppercaseChar().toString()
                    } else {
                        // no separator - either end of list, or first letters of before/after are the same
                        null
                    }
                },
                executor
            )
        },
        executor
    )
}
import androidx.paging.insertSeparatorsAsync
import androidx.paging.map
import androidx.paging.rxjava2.insertSeparatorsAsync

open class UiModel
data class ItemUiModel(val item: Item) : UiModel()
data class SeparatorUiModel(val char: Char) : UiModel()

/*
 * Create letter separators in an alphabetically sorted list of Items, with UiModel objects.
 *
 * For example, if the input is (each an `Item`):
 *     "apple", "apricot", "banana", "carrot"
 *
 * The operator would output a list of UiModels corresponding to:
 *     "A", "apple", "apricot", "B", "banana", "C", "carrot"
 */
pagingDataStream.map { pagingData ->
    // map outer stream, so we can perform transformations on each paging generation
    pagingData
        .map { item ->
            ItemUiModel(item) // convert items in stream to ItemUiModel
        }
        .insertSeparatorsAsync(
            AsyncFunction<AdjacentItems<ItemUiModel>, UiModel?> {
                Futures.submit(
                    Callable<UiModel> {
                        val (before, after) = it!!
                        if (after != null &&
                            before?.item?.label?.first() != after.item.label.first()
                        ) {
                            // separator - after is first item that starts with its first letter
                            SeparatorUiModel(after.item.label.first().uppercaseChar())
                        } else {
                            // no separator - either end of list, or first letters of before/after are the same
                            null
                        }
                    },
                    executor
                )
            },
            executor
        )
}
Parameters
@NonNull AsyncFunction<@NonNull AdjacentItems<@NonNull T>, R> generator

AsyncFunction used to generate separator between two AdjacentItems or the header or footer if either AdjacentItems.before or AdjacentItems.after is null.

@NonNull Executor executor

Executor to run the AsyncFunction in.

PagingDataFutures.mapAsync

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingDataFutures.mapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull AsyncFunction<@NonNull T, @NonNull R> transform,
    @NonNull Executor executor
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.

Parameters
@NonNull AsyncFunction<@NonNull T, @NonNull R> transform

AsyncFunction to transform an item of type T to R.

@NonNull Executor executor

Executor to run the AsyncFunction in.

PagingDataTransforms.filter

public final @NonNull PagingData<@NonNull T> <T extends Object> PagingDataTransforms.filter(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Executor executor,
    @NonNull Function1<@NonNull T, @NonNull Boolean> predicate
)

Returns a PagingData containing only elements matching the given predicate.

See also
filter

PagingDataTransforms.flatMap

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingDataTransforms.flatMap(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Executor executor,
    @NonNull Function1<@NonNull T, @NonNull Iterable<@NonNull R>> transform
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

See also
flatMap

PagingDataTransforms.insertFooterItem

public final @NonNull PagingData<@NonNull T> <T extends Object> PagingDataTransforms.insertFooterItem(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull TerminalSeparatorType terminalSeparatorType,
    @NonNull T item
)

Returns a PagingData containing each original element, with the passed footer item added to the end of the list.

The footer item is added to a loaded page which marks the end of the data stream in the LoadType.APPEND direction, either by returning null in PagingSource.LoadResult.Page.nextKey. It will be removed if the last page in the list is dropped, which can happen in the case of loaded pages exceeding PagingConfig.maxSize.

Note: This operation is not idempotent, calling it multiple times will continually add more footers to the end of the list, which can be useful if multiple footer items are required.

Parameters
@NonNull TerminalSeparatorType terminalSeparatorType

TerminalSeparatorType used to configure when the header and footer are added.

@NonNull T item

The footer to add to the end of the list once it is fully loaded in the LoadType.APPEND direction.

See also
insertHeaderItem

PagingDataTransforms.insertHeaderItem

public final @NonNull PagingData<@NonNull T> <T extends Object> PagingDataTransforms.insertHeaderItem(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull TerminalSeparatorType terminalSeparatorType,
    @NonNull T item
)

Returns a PagingData containing each original element, with the passed header item added to the start of the list.

The header item is added to a loaded page which marks the end of the data stream in the LoadType.PREPEND direction by returning null in PagingSource.LoadResult.Page.prevKey. It will be removed if the first page in the list is dropped, which can happen in the case of loaded pages exceeding PagingConfig.maxSize.

Note: This operation is not idempotent, calling it multiple times will continually add more headers to the start of the list, which can be useful if multiple header items are required.

Parameters
@NonNull TerminalSeparatorType terminalSeparatorType

TerminalSeparatorType used to configure when the header and footer are added.

@NonNull T item

The header to add to the front of the list once it is fully loaded in the LoadType.PREPEND direction.

See also
insertFooterItem

PagingDataTransforms.insertSeparators

public final @NonNull PagingData<@NonNull R> <R extends Object, T extends R> PagingDataTransforms.insertSeparators(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull TerminalSeparatorType terminalSeparatorType,
    @NonNull Executor executor,
    @NonNull Function2<T, T, R> generator
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

Note that this transform is applied asynchronously, as pages are loaded. Potential separators between pages are only computed once both pages are loaded.

Kotlin callers should instead use the suspending extension function variant of insertSeparators

/*
* Create letter separators in an alphabetically sorted list.
*
* For example, if the input is:
* "apple", "apricot", "banana", "carrot"
*
* The operator would output:
* "A", "apple", "apricot", "B", "banana", "C", "carrot"
*/
pagingDataStream.map(pagingData ->
// map outer stream, so we can perform transformations on each paging generation
PagingDataTransforms.insertSeparators(pagingData, bgExecutor,
(@Nullable String before, @Nullable String after) -> {
if (after != null && (before == null
|| before.charAt(0) != after.charAt(0))) {
// separator - after is first item that starts with its first
// letter
return Character.toString(
Character.toUpperCase(after.charAt(0)));
} else {
// no separator - either end of list, or first
// letters of items are the same
return null;
}
}));

/*
* Create letter separators in an alphabetically sorted list of Items, with UiModel
* objects.
*
* For example, if the input is (each an `Item`):
* "apple", "apricot", "banana", "carrot"
*
* The operator would output a list of UiModels corresponding to:
* "A", "apple", "apricot", "B", "banana", "C", "carrot"
*/
pagingDataStream.map(itemPagingData -> {
// map outer stream, so we can perform transformations on each paging generation

// first convert items in stream to UiModel.Item
PagingData<UiModel.ItemModel> itemModelPagingData = PagingDataTransforms.map(
itemPagingData, bgExecutor, UiModel.ItemModel::new);

// Now insert UiModel.Separators, which makes the PagingData of generic type UiModel
return PagingDataTransforms.insertSeparators(
itemModelPagingData, bgExecutor,
(@Nullable UiModel.ItemModel before, @Nullable UiModel.ItemModel after) -> {
if (after != null && (before == null
|| before.item.label.charAt(0) != after.item.label.charAt(0))) {
// separator - after is first item that starts with its first letter
return new UiModel.SeparatorModel(
Character.toUpperCase(after.item.label.charAt(0)));
} else {
// no separator - either end of list, or first
// letters of items are the same
return null;
}
});
});

public class UiModel {
static class ItemModel extends UiModel {
public Item item;
ItemModel(Item item) {
this.item = item;
}
}
static class SeparatorModel extends UiModel {
public char character;
SeparatorModel(char character) {
this.character = character;
}
}
}
Parameters
@NonNull TerminalSeparatorType terminalSeparatorType

TerminalSeparatorType used to configure when the header and footer are added.

@NonNull Executor executor

Executor to run the generator function in.

@NonNull Function2<T, T, R> generator

Generator function used to construct a separator item given the item before and the item after. For terminal separators (header and footer), the arguments passed to the generator, before and after, will be null respectively. In cases where the fully paginated list is empty, a single separator will be added where both before and after items are null.

PagingDataTransforms.map

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingDataTransforms.map(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Executor executor,
    @NonNull Function1<@NonNull T, @NonNull R> transform
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.

See also
map

PagingRx.filterAsync

public final @NonNull PagingData<@NonNull T> <T extends Object> PagingRx.filterAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Boolean>> predicate
)

Returns a PagingData containing only elements matching the given predicate.

PagingRx.filterAsync

public final @NonNull PagingData<@NonNull T> <T extends Object> PagingRx.filterAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Boolean>> predicate
)

Returns a PagingData containing only elements matching the given predicate.

PagingRx.flatMapAsync

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingRx.flatMapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Iterable<@NonNull R>>> transform
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

PagingRx.flatMapAsync

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingRx.flatMapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull Iterable<@NonNull R>>> transform
)

Returns a PagingData of all elements returned from applying the given transform to each element, as it is loaded.

PagingRx.insertSeparatorsAsync

public final @NonNull PagingData<@NonNull R> <T extends R, R extends Object> PagingRx.insertSeparatorsAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function2<T, T, @NonNull Maybe<@NonNull R>> generator
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

Note that this transform is applied asynchronously, as pages are loaded. Potential separators between pages are only computed once both pages are loaded.

import androidx.paging.insertSeparatorsAsync
import androidx.paging.rxjava2.insertSeparatorsAsync

/*
 * Create letter separators in an alphabetically sorted list.
 *
 * For example, if the input is:
 *     "apple", "apricot", "banana", "carrot"
 *
 * The operator would output:
 *     "A", "apple", "apricot", "B", "banana", "C", "carrot"
 */
pagingDataStream.map { pagingData ->
    // map outer stream, so we can perform transformations on each paging generation
    pagingData.insertSeparatorsAsync { before: String?, after: String? ->
        Maybe.fromCallable<String> {
            if (after != null && before?.first() != after.first()) {
                // separator - after is first item that starts with its first letter
                after.first().uppercaseChar().toString()
            } else {
                // no separator - either end of list, or first letters of before/after are the same
                null
            }
        }.subscribeOn(Schedulers.computation())
    }
}
import androidx.paging.insertSeparatorsAsync
import androidx.paging.map
import androidx.paging.rxjava2.insertSeparatorsAsync

open class UiModel
data class ItemUiModel(val item: Item) : UiModel()
data class SeparatorUiModel(val char: Char) : UiModel()

/*
 * Create letter separators in an alphabetically sorted list of Items, with UiModel objects.
 *
 * For example, if the input is (each an `Item`):
 *     "apple", "apricot", "banana", "carrot"
 *
 * The operator would output a list of UiModels corresponding to:
 *     "A", "apple", "apricot", "B", "banana", "C", "carrot"
 */
pagingDataStream.map { pagingData ->
    // map outer stream, so we can perform transformations on each paging generation
    pagingData
        .map { item ->
            ItemUiModel(item) // convert items in stream to ItemUiModel
        }
        .insertSeparatorsAsync { before: ItemUiModel?, after: ItemUiModel? ->
            Maybe.fromCallable<UiModel> {
                if (after != null && before?.item?.label?.first() != after.item.label.first()) {
                    // separator - after is first item that starts with its first letter
                    SeparatorUiModel(after.item.label.first().uppercaseChar())
                } else {
                    // no separator - either end of list, or first letters of before/after are the same
                    null
                }
            }.subscribeOn(Schedulers.computation())
        }
}

PagingRx.insertSeparatorsAsync

public final @NonNull PagingData<@NonNull R> <T extends R, R extends Object> PagingRx.insertSeparatorsAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function2<T, T, @NonNull Maybe<@NonNull R>> generator
)

Returns a PagingData containing each original element, with an optional separator generated by generator, given the elements before and after (or null, in boundary conditions).

Note that this transform is applied asynchronously, as pages are loaded. Potential separators between pages are only computed once both pages are loaded.

import androidx.paging.insertSeparatorsAsync
import androidx.paging.rxjava2.insertSeparatorsAsync

/*
 * Create letter separators in an alphabetically sorted list.
 *
 * For example, if the input is:
 *     "apple", "apricot", "banana", "carrot"
 *
 * The operator would output:
 *     "A", "apple", "apricot", "B", "banana", "C", "carrot"
 */
pagingDataStream.map { pagingData ->
    // map outer stream, so we can perform transformations on each paging generation
    pagingData.insertSeparatorsAsync { before: String?, after: String? ->
        Maybe.fromCallable<String> {
            if (after != null && before?.first() != after.first()) {
                // separator - after is first item that starts with its first letter
                after.first().uppercaseChar().toString()
            } else {
                // no separator - either end of list, or first letters of before/after are the same
                null
            }
        }.subscribeOn(Schedulers.computation())
    }
}
import androidx.paging.insertSeparatorsAsync
import androidx.paging.map
import androidx.paging.rxjava2.insertSeparatorsAsync

open class UiModel
data class ItemUiModel(val item: Item) : UiModel()
data class SeparatorUiModel(val char: Char) : UiModel()

/*
 * Create letter separators in an alphabetically sorted list of Items, with UiModel objects.
 *
 * For example, if the input is (each an `Item`):
 *     "apple", "apricot", "banana", "carrot"
 *
 * The operator would output a list of UiModels corresponding to:
 *     "A", "apple", "apricot", "B", "banana", "C", "carrot"
 */
pagingDataStream.map { pagingData ->
    // map outer stream, so we can perform transformations on each paging generation
    pagingData
        .map { item ->
            ItemUiModel(item) // convert items in stream to ItemUiModel
        }
        .insertSeparatorsAsync { before: ItemUiModel?, after: ItemUiModel? ->
            Maybe.fromCallable<UiModel> {
                if (after != null && before?.item?.label?.first() != after.item.label.first()) {
                    // separator - after is first item that starts with its first letter
                    SeparatorUiModel(after.item.label.first().uppercaseChar())
                } else {
                    // no separator - either end of list, or first letters of before/after are the same
                    null
                }
            }.subscribeOn(Schedulers.computation())
        }
}

PagingRx.mapAsync

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingRx.mapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull R>> transform
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.

PagingRx.mapAsync

public final @NonNull PagingData<@NonNull R> <T extends Object, R extends Object> PagingRx.mapAsync(
    @NonNull PagingData<@NonNull T> receiver,
    @NonNull Function1<@NonNull T, @NonNull Single<@NonNull R>> transform
)

Returns a PagingData containing the result of applying the given transform to each element, as it is loaded.