How to convert a List<Object> to PagedList<Object> and vice-versa?
Asked Answered
Q

3

28

PagedList<Object> is used for Android's cool paging library. To make the question as minimal as possible : If i have a list of strings like

  List<String> stringList; // it consists of 200 strings

I want to convert stringList to type PagedList<String> like

  PagedList<String> pagedStringList;

And also if i have a PagedList<Object> how can convert it to a List<Object> ? I went through this for reference

If i try the other way round ....

How can I convert List<Object> into DataSource.Factory<Integer, Object> ..so that indirectly i can convert it into PagedList<> ?

From DataSource.Factory<Integer, Object> I can convert to PagedList<> but how can I convert list into PagedList<> ?

Quinlan answered 25/4, 2018 at 19:34 Comment(3)
did you manage to make this work?Siskin
will try it and let you know..i know lil kotlin though..:)Quinlan
awokay :) I added the java version to be more helpful, hope it worksSiskin
S
12

I'll start with the easier part, if you want to converter a PagedList<> to a a List<> you can use the snapshot() method, as you can seen in the docs it retuns:

Returns an immutable snapshot of the PagedList in its current state.A PagedList snapshot is simply an immutable shallow copy of the current state of the PagedList as a List.

Now as for the other way around you'll need to use PagedList.Builder and for that you'd need a DataSource to create the PagedList. So a avery basic dataSource that would manage your static list would look like this:

StringDataSource.kt

class StringDataSource(val provider: StringListProvider) : PageKeyedDataSource<Int, String>() {
    override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, String>) {
        val list = provider.getStringList(0, params.requestedLoadSize)
        callback.onResult(list, 1, 2)
    }

    override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, String>) {
        val list = provider.getStringList(params.key, params.requestedLoadSize)
        callback.onResult(list, params.key + 1)
    }

    override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, String>) {
        val list = provider.getStringList(params.key, params.requestedLoadSize)
        val nextIndex = if (params.key > 1) params.key - 1 else null
        callback.onResult(list, nextIndex)
    }

    companion object {
        const val PAGE_SIZE = 20
    }
}

As you can see you need to override the three methods loadInitial, loadAfter and loadBefore in order to tell the datasource how to load the cunks of data from the list. I've wrapped you list in a provider class just for organization purposes.

StringListProvider.kt

class StringListProvider(val list: List<String>) {


    fun getStringList(page: Int, pageSize: Int): List<String> {

        val initialIndex = page * pageSize
        val finalIndex = initialIndex + pageSize
        //TODO manage index out of range
        return list.subList(initialIndex, finalIndex)
    }
}

To use the data source to generate the PagedList you need to build a simple configuration with PagedList.Config.Builder:

    val myConfig = PagedList.Config.Builder()
            .setInitialLoadSizeHint(PAGE_SIZE)
            .setPageSize(PAGE_SIZE)
            .build()

And then pass that to the PagedList.Builder with the datasource:

    val pagedStrings: PagedList<String> = PagedList.Builder<Int, String>(StringDataSource(StringListProvider(originalStrings)), myConfig)
            .setInitialKey(0)
            .build()

Now you have a PagedList in pagedStrings.

The same thing in java:

StringListProvider.java

public class StringListProvider {

    private List<String> list;

    public StringListProvider(List<String> list) {
        this.list = list;
    }

    public List<String> getStringList(int page, int pageSize) {
        int initialIndex = page * pageSize;
        int finalIndex = initialIndex + pageSize;

        //TODO manage out of range index

        return list.subList(initialIndex, finalIndex);
    }
}

StringDataSource.java

public class StringDataSource extends PageKeyedDataSource<Integer, String> {

    public static final int PAGE_SIZE = 20;
    private StringListProvider provider;

    public StringDataSource(StringListProvider provider) {
        this.provider = provider;
    }

    @Override
    public void loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, String> callback) {
        List<String> result = provider.getStringList(0, params.requestedLoadSize);
        callback.onResult(result, 1, 2);
    }

    @Override
    public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, String> callback) {
        List<String> result = provider.getStringList(params.key, params.requestedLoadSize);
        Integer nextIndex = null;

        if (params.key > 1) {
            nextIndex = params.key - 1;
        }
        callback.onResult(result, nextIndex);
    }

    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, String> callback) {
        List<String> result = provider.getStringList(params.key, params.requestedLoadSize);
        callback.onResult(result, params.key + 1);
    }
}

Config generation

    PagedList.Config myConfig = new PagedList.Config.Builder()
            .setInitialLoadSizeHint(PAGE_SIZE)
            .setPageSize(PAGE_SIZE)
            .build();

List convertion

    List<String> myList = new ArrayList<>();
    StringListProvider provider = new StringListProvider(myList);
    StringDataSource dataSource = new StringDataSource(provider);
    PagedList<String> pagedStrings = new PagedList.Builder<Integer, String>(dataSource, myConfig)
            .setInitialKey(0)
            .build();
Siskin answered 13/5, 2018 at 11:31 Comment(3)
When you build PagedList object you need to set setNotifyExecutor and setFetchExecutor methods, otherwise crashDiplomatics
As nAkhmedov mentioned, you will need to set a notify and fetch executor. Here is how to create a UI thread Executor: https://mcmap.net/q/504779/-capturing-executor-for-current-threadUnto
Thank you. Regarding the setNotifyExecutor and the setFetchExecutor, this page has a good implementation: [riyaz-ali.github.io/android-support-paging.html]Azarcon
R
3

I have converted a List<Object> to PagedList<Object> by this code in kotlin i think this code can help you

  1. build config

    private val config = PagedList.Config.Builder()
            .setEnablePlaceholders(false)
            .setPageSize(LIST_SIZE)
            .build()
    

2.create these classes for convert and return my PagedList<Object>

     class ListDataSource<T>(private val items: List<T>) : PositionalDataSource<T>() {
            override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<T>) {
                callback.onResult(items, 0, items.size)
    }

            override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<T>) {
                val start = params.startPosition
                val end = params.startPosition + params.loadSize
                callback.onResult(items.subList(start, end))
    }
}

        // UiThreadExecutor implementation example
       class UiThreadExecutor : Executor {
            private val handler = Handler(Looper.getMainLooper())
            override fun execute(command: Runnable) {
               handler.post(command)
    }
}
  1. Pass val myList: List<Object> by config and get PagedList<Object>

    val pagedList = PagedList.Builder(ListDataSource(myList), config)
                                .setNotifyExecutor(UiThreadExecutor())
                                .setFetchExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
                                .build()
    
Roble answered 13/6, 2020 at 6:18 Comment(0)
E
0

This is how I solve my problem, this might help.

val items = List<Item>.... //this can be equal to your mutable list
val config = PagedList.Config.Builder()
                        .setPageSize(items.size)
                        .setEnablePlaceholders(false)
                        .setInitialLoadSizeHint(items.size)
                        .build()

val pagedList = PagedList.Builder(ListDataSource(items),config)
                .setNotifyExecutor (UiThreadExecutor ())
                .setFetchExecutor (AsyncTask.THREAD_POOL_EXECUTOR)
                .build ()


class UiThreadExecutor: Executor {
        private val handler = Handler (Looper.getMainLooper ())
        override fun execute (command: Runnable) {
            handler.post (command)
        }
    }

class ListDataSource (private val items: List<Item>): PageKeyedDataSource<Int, Item>() {
            override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Item>) {
                callback.onResult (items, 0, items.size)
            }
    
            override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Item>) {
    
            }
    
            override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, Item>) {
    
            }
        }

Other Resources: android - how to convert list to pagedlist

Excursionist answered 4/8, 2020 at 3:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.