Getting on the same page with Paging 3 with Florina Muntenescu

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay so looks like you can see the slides and stuff so um yeah let's crack this book open so paging library the paging library helps you load large sets of data gradually and gracefully reducing network usage and system resources so previously we've released paging to api but the feedback that we got is that well paging to api is a good start but a lot of developers told us that they wanted more so this is why we launched paging three a complete rewrite of the library based on content core routines and flow adding the features that you asked for like their error handling easier transformations of your data like map or filter and support for common features like list separators headers and footers we also wanted to make sure that paging is easier to integrate in your app so this is also one of the features of the of paging three if you're still developing in java i know i mentioned called content corrections and flow but paging also has support for rxjava live data and listenable features okay let me start by telling you why i like beijing 3 library when you load daytime pages there's a lot of things you need to do you need to keep track of the keys to retrieve the next or previous page you have to make sure that you're correct you're requesting the correct next page when the user scrolls to the end of the loaded data and you also want to make sure that you're preventing duplicate requests well paging does all of this for you so there's a lot to like it also tracks loading state and allows you to display it in a recycle of your list item or elsewhere in your ui and provides easy retry functionality for failed loads refreshing your list is also only one method call away paging makes it easier to transform your data before displaying it it offers common operations like map or filter no matter whether you're using flow like data or rx java adding separators with your data is also greatly simplified we also made several paging three components backwards compatible with paging two so if you're already using paging in your app then you can migrate incrementally okay let's look at um at a practical example so let's say that we have an app that displays all the good dogs we get the dogs from a good doggos api that supports inbox paid special pagination so let's go over the paging components we need to implement and see how they fit in your architecture so the examples i'm going to share from now on are going to be in kotlin but in our documentation we have examples in java as well so check those out for the java version okay so paging library integrates directly in the recommended android app architecture in each layer of your application in your data layer and more precisely in your repository you will work with a paging source or a remote mediator then in the view model using pager you create a flow of paging data which in the ui layer you will use to bind a paging data adapter to populate a recycler view okay let's look at these components individually and let's start with the data source so if you're loading data from a single source like network local database or file implement the paging source if you're using room then paging source is implemented for you if you're loading data from a layered source like a network data source with local database cache then implement a remote mediator to retrieve and save remote data and also a paging source for the local database cache okay let's look further a little bit at the paging source and see how the implementation will look like so paging source is the class that defines the source of paging data and how to retrieve that data from a single source you will implement the load method to retrieve page data from your data source since load is a suspend function you can call other suspend functions here such as a network or a database call uh what you need to return from load is um the loaded data together with information about next and previous keys or error if the load failed when your next and previous keys are given by the network response like what i have on the screen right now all you have to do is just pass those in but if you're using indices for example you'll have to compute those yourself so based on the keys you set and the direction of loading the paging library will set the value of the key field in the load parameters so this means that when you have to build a network call that key is just provided so you just need to use it okay so often just having one data source is not enough but rather you want to have a layer data source that loads from both network and database and using network and database is great these two components work great together you get to have fresh data from the network with all the benefits of the local cache like offline support fast resume and decreased network traffic but implementing this by yourself we know it's not easy so we often saw this kind of an architecture where a repository would rely on a connected state so whether a network is connected or not to decide whether to get the data from the network or from the database but there are several problems with this approach with this approach so if you just use a connected flag you kind of oversimplify the problem because individual requests can succeed or fail and you know we're saving data in the database but we're actually not using it even um even if it's present but we're always requesting data from the network okay so what's a better solution well another solution is to always treat the database as the source of truthwork that you are and only request more from the network on first load or when the data from the database is exhausted well paging three was built to support this exact architecture so here's what we need to do to implement it first we have to create a paging source that reads from the database here i'm using room that supports this out of the box all we need to do is return a paging source from the dial query then to request data from the network and save it paging offers the remote mediator class this load method will be triggered whenever we need to load more data so here we will request data from the network and save it to the database well to request data from the network you need to construct the key for it so while paging can't really know what that key is it will give you the tools you need to compute it the other these two load parameters so we are the load type and the paging state so let's look a little bit at these two parameters so low type gives you information about where we're trying to load data based on the data that's been displayed so far so for example load type refresh is going to be called for the initial load um so when the refresh for the initial load when refresh was called uh maybe from a pulse refresh for example or when paging source was invalidated then low type can also be prepend when we scrolled up or opens when we scroll down and we need to load data when we need to append data at the bottom of our list uh then the other parameter of load is the paging state well paging state actually gives you several pieces of information but out of all of these there's one that i really find important and this is the list of loaded pages until then so this means that you'll have access to all the pages that were loaded in the database so now that we have the pages that were loaded in the database means that we can compute the pages that need to be requested next so for example if we're appending we rely on the on on the last item that was loaded to compute the next page key or if we're pre-pending then we rely on the first item of the first page that was loaded so after we compute the key we can just request data from the network and save it in the database so after we um we save the data in the database we'll also have to inform paging whether there is more data to load or not so for example if there are no more doggos in the database there are no more doggos back from the service sorry then we know we've reached the end of the list so this means that we'll just return a success with and the pagination true and similarly we will have to tell paging whether an error occurs when retrieving the data and that's all that's all you need to do when implementing a remote mediator so now i looked at the repository layer let's look at the at the view model layer so let's see how we can configure paging to use these data source so the primary entry point for paging is the pager we construct the pager based on a paging configuration and the function that creates a data source if you're using a remote mediator and the database is your source of truth make sure you pass them both like i have here in the slide page and config allows you to set several parameters but the page size is actually the one that's so that's mandatory and represents the number of items loaded at once from the paging source so you'll decide on the paging side on the page size based on how your ui looks like so in general we recommend having at least three screens of data to ensure that you're doing like an optimum number of requests not too many but not too little either so let's go a little bit more in depth with pagey config and see all the other parameters that can be configured so another one is the prefetch distance so this one defines um how close to the end of the list should the request for the next page should be triggered by default whenever we are at page size distance to the end of the list paging will uh trigger a new request then whether we should enable placeholders or not so um let's see what this means because i think this is actually a quite interesting approach so usually what you would regularly see in an app is something like this so uh your list gets loaded and you see that um your scroll is quite big uh but then as you're scrolling towards the end you're loading more data and then uh your scroll bar becomes smaller because the data has been loaded well if you enable placeholders the scroll bar size will be correct from the beginning and then if you're scrolling towards an area where items haven't been loaded yet you will just get null items back so this means that in your adapter you will know well if i have a null item then this means that i should display a placeholder and then whenever paging is able to load that new data it will omit a new list with the right elements populated so placeholders using placeholders has positives and negatives so the good thing is that users can scroll past what's loaded and the scroll bar just looks correct from the beginning and also you don't need to show a loading spinner separately and take care of all of that functionality because placeholders are the ones that show the user that you're still loading that data but on the other side the problem with the placeholders is that items need to be should have the same size so this wouldn't support items that have different sizes and your adapter needs to know how to handle null items and i think the most important one is that this this placeholders only fits for paging sources that can count items so if you have an infinite scrolling list this isn't really uh this isn't possible okay um then another configuration is initial load size so this is the number of pages that should be loaded at the beginning then when you're first opening the application for example when you're first loading your data another one is max size so by default paging will keep in memory all the data that needs to be displayed but if you know that you're having that you have a really large set of data maybe an infinite scrolling list you probably don't want to keep all of that data in memory but rather you want to tell paging that it it should only keep a specific amount of items i don't know a thousand items maybe in memory this is something that you would have to decide based on the items that you need to display um yeah so this max size allows you to configure how many items are kept in memory by page and then the last one is the jump threshold that's related to when you're scrolling past items that haven't been loaded yet oh um this is quite a lot and actually this is what i like about paging the fact that by default if you just want to use it for simple cases it's quite easy you just set the page size and that's it but then if you want to have some extra more advanced configuration paging allows you to do that okay so um i said that the paging works with uh with causing core teams and so this means that when you're constructing your pager um you can return flow but pager can also return a flowable or another bubble if you're working with rxjava too or live data okay now that we've constructed our flow of paging data let's see how we connect it to a recycler view so to do this we will implement a paging data adapter this actually doesn't look any different to how you would implement a regular list adapter but under the hood it provides the functionality needed to support paging data objects okay what do we do in our ui so in our activity or fragment you would just collect the flow and then submit uh the data to the adapter that's all so for example i think this is an activity so we're launching a new quality in the lifecycle scope and then we're collecting the latest emissions of the flow and then submitting the paging data to the adapter so this is how each of the paging components integrates in our amp architecture but often we want to perform some transformations to the data before displaying it well transforming paging data streams is very similar to the way we would work with any other data stream so let's say that we only want to display playful doggos well to do this we need to map the flow and filter the paging data that is all if you're working with streams probably you will do something similar to filter other streams now let's say that our list is order by breed and what we want to do is to insert separators and to be able to separate the docs by breathing well when adding less separators we transform the paging data to insert separator objects into the list but this means that now our ui needs to support multiple data types it needs to know how to display a separator and how to display a doggo so to do this we create a new ui model that defines a dollar and a separator item so then we need to transform our separator items first we need to sorry we need to transform our items so first we need to transform the flow of dogs into a flow of ui model of dogos next to be able to uh modify the list to insert separators we again transform the list we call map and then we call insert separators um so when so here for insert separators we actually get a callback for each individual pair of items so then we can decide whether do we want to insert a separator between them or not so here for example i'm checking whether uh the name of the breed between two light two items is different and if it is then i'm just inserting a new separator okay so we've added separators but let's say that we want to add a header or footer to our list so how do we do that how do we add that header well the first thing we need to do is actually expand the ui model to support the new view geotypes so to support the new header and footer we need to display as part of the list and then we just transform the paging data to also insert the header item and the footer item okay inserting a header or footer is not that complicated but what if in our footer we want to display the load state so let's say that we want to display a progress spinner while the list is loading or and a retry button for error so these load elements are actually diff are actually separate from the actual list content right they don't have any connections with with the dogs that we want to display so this means that we don't need to modify the list to add these load related items so to make it easier to work with a load state object paging offers a new recycle of your adapter type load state adapter so to be able to support loading headers or footers you'll have to implement the load state adapter so here you would just have to create your view holder and in your view holder you will need to know how to react or what to display in different load states and then you will have to update the adapter in your ui to also add the footer item the header item or both header or footer item so that's all but what if you want more flexibility let's say that we do want to display the load states but not inside a header footer let's say that for loading you want to hide a list and show some fancy toggle animation or in case of error you want to show a retry button or maybe you want to show a snack bar for error and then only after you finish loading data successfully you want to show the list and hide the progress indicator or retry button even more you might have you might want to have different behaviors depending on where the data is coming from if it's from a paging source or from a remote mediator maybe if it's coming from a remote mediator and you get an error you i don't know you want to show something to the user saying that hey you don't have any internet connection go somewhere where there's better reception or something also not all load types are the same so maybe you want to show different messages depending on where you want to load the data so maybe if you're if you have an error later loading data for the first time in refresh you might want to show the data differently so asian gives you all of this flexibility and gives you information about all of these load states and it does that in a load states listener so you can either implement this listener but it also offers a flow of a load state so here what it does it returns a combined load state object so back to our case where we said that we want to only show the list if the refresh succeeds it means that we will be we are able to decide on the visibility of our list based on uh the states of the refresh so if the refresh is not loading it means that we have finished loading the list and we have finished loading the list successfully without an error then we can show it similarly if we only want to show the progress bar during the initial load or refresh then we rely on refresh state is loading and if you want to show the retry button for error but only for the initial load or refresh cases then we check whether refresh is low state error and that's all okay um going a little bit back to what i was saying with the low state adapter but also uh here so i was saying that you could just display a retry button but i never actually told you what's up with that retry button well um paging provides a retry function on the adapter so whenever you want to do this kind of retry calls you can just do it from the from the ui uh but keep in mind that retry only requires failed loads so if your call if your network call maybe was successful and you're calling retry nothing will happen only if error was returned probably if you're trying to do retry if even if data was uh was returned successfully you actually want to do a refresh so refresh is the function that will actually trigger a reload from scratch completely and what's important to note is also that this doesn't affect prepend or append state only refresh and this is this should be implemented for ui driven refresh signals so this means that this is something that should be called when you have a retry a refresh button sorry in your ui or when you're implementing a pulse refresh functionality but not somewhere from your data or business layer but just from the ui cool okay so we've seen all these types of transformations of paging data but transforming data can be expensive especially if you have a lot of items in memory and you're not using this max items in the configuration so you want to make sure that you're not executing transformations on on big big sets of data on every configuration change when you start collecting the flow but rather just once well to help with this paging three offers the cashed in methods the caching should be done after all the transformations have been performed so after all your math and so on have been performed so if you're using opencore routines then you have to cache the data in the viewmodelscope if you're using rx java you'll also have to use the vmodoscope for caching data so by default paging because paging depends on causing proteins and flow it means that it will also bring the coroutines artifacts with it so if you're implementing this in your view model then your view model should already have access to the view model scope so even if you're not working with coroutines and rather with rx java it should still be easy to pass it and then similarly if you're using live data you can either cache the data in the view model scope or in the context of the life cycle object okay so this was quite a lot so let's recap a little bit everything i said so paging three makes it easier to work with large sets of data whether you're loading from network from the database an in-memory cache or some combination of all of these the library is built with qualities and flow making it easy to call suspend functions and work with streams of data it has built-in apis to transform data add separators headers and footers displaying the loading states and retrying fail requests and finally it's compatible with paging two so it's easy to migrate so paging three right now is still an alpha so we need your help to make it better so please try it out but to try it out to get started uh you can find out more about paging from the paging three documentation or by checking out the codelab and the sample and then let us know what we missed let us know what you need what use cases you find that you think are not supported by paging by creating an issue on the issue tracker so that was it i will close the paging chapter for now and uh yeah i hope the paging library helps you gradually and gracefully load all the good doggos thanks for watching and now i'm hoping we can get some questions yeah probably two three minutes to kind of like write their thoughts out it's yeah you did really well serena yay thank you that was a really solid talk thank you nice there already a few questions oh yeah you can give a few more minutes because that way people like to upload them too and that way it's so democracy right awesome yeah that's that's that's good that you can hop back in if you want i saw you kind of like he shows up and then it's like i'm out i was actually just trying to test my camera i just turned it back on and then i saw oh no i'm on stage it's working we can tell that it's working yeah questions coming up like this oh we got eight votes in that's pretty high number yeah nice oh you can start whenever you feel i it seems like it feels pretty active but the questions are are adding up so maybe we can uh i can start answering and then we'll see okay can we display header ah okay wait i will go with the question that became uh on top now okay with this approach can the list separators be collapsible for instance can all the dog breeds be collapsed and then when clicked on then expands the dogs in that category um not that i know of i have to admit i haven't implemented a collapsible list since the list view era um but i'm not would be sure answer sorry um probably that would be i don't know i would try to avoid implementing it as a list of lists so i don't know i would have to play around with it to uh to find out but actually this is a really good question thank you um okay i'll go to the next one can we display headers with titles instead of simple separators uh i wonder what this means so instead of the separator you just want to have one header i'm hoping that can be implemented with the add header or in the separators you want to set the text if you want to set a text you can in the separators you can define any text you want if you're talking about sticky headers uh this is not supported for now not by default it's not that easy to implement so you would have to implement this yourself okay um how this new paging sorry just kept on jumping okay do you have any suggestions for using paging with firestar um so because paging 3 supports as a paging source anything you want then i would expect that in the paging source implementation you can use firestore by default from what i know firestore doesn't have a paging three um support so you would just have to implement this yourself but i think it's possible um okay how will this new paging adapter interact with concat adapter well uh actually uh paging uses contact adapter under the hood um so let me switch quickly to the slides so for example um here for displaying load state um so what we were doing in the adapter sorry here we are doing adapter with a load footer and or adapter with load state header so actually what paging does under the hood is um using a concat adapter and adding uh these new adapters that we're creating so this means that you can just concatenate it um i would guess you want to add some other stuff apart from the paging list i guess this should be possible um i haven't tried it but i expect that it's possible um i will skip the slack link uh for now or should i open it no no that skip it that was just for letting me just remodel it yeah cool um are there built-in resolution strategies if local network data gets out of sync uh different order indices duplicates or is it up to you to implement them yourself in your repo or div callback well local and network data shouldn't get out of sync because the local data the database should be your source of truth so this means that your network data should should then afterwards be saved in the database if you want some different strategies like for example i don't know you have to have some conflict resolution maybe uh between the data coming from the network and what's in the database that's something that you would have to implement because beijing can't know how your data looks like and how you want to i don't know merged items or things like this okay is there any way to implement sticky headers out of the box with paging three uh a lot for now um but the team consider this but it's it's not an easy problem to solve um but yeah i'll bring this up to the team maybe maybe we convince them to implement it um okay uh paging two didn't seem to gain a lot of popularity any idea why um well i'm happy you liked it shalom uh i think that the flexibility was one of the features that was missing so the fact that uh it wasn't as easy as it is now to map data and to transform data um i do know that there were some confusions about the paging source and how different elements fit in our architecture i'm hoping this is much clearer now or at least for me it was much much more clear when i started using it for the first time so yeah okay um if you want to keep android dependencies out of the repository layer or lower would the view model be the best place to set up the pager based on the flow from the repo i was actually trying to get this answer uh now so right now paging um uh has like a i think a common library but that is still an android dependency although i know classes like page and source or pager and so on are actually just kotlin classes they don't depend on android um so depends i would say depends on how you're actually separating your layers if you're thinking about module separation or just android dependencies separation so the pager itself doesn't depend on anything android related the paging adapter of course depends on on the list not on the list adapter sorry on the recycler view adapter so there is the part where you would have android dependencies but apart from that if you're just thinking about whether you can write unit tests or not that should be possible with whether you're working with um the pager in the view model or in the in the repository layer i hope it helped um okay uh is it running on kotlin yes actually um so you might have noticed there that even when you were working when i was showing the rx java or the live data examples um you had to pass the model scope so that's because under the hood what we're doing is uh actually just converting the flows to rxjava or live data objects so i know i would say that the the backbone of paging three is coupling coroutines and flow oh how can i remove an item from the adapter you don't really remove an item from the adapter right you remove an item from your list so this means that you would i don't know let's say that you click on a button and an item needs to be removed this means that your you would tell your data source that that item doesn't exist anymore so this means that the pager will end up the paging will end up emitting a new flow of items without that new item and therefore the adapter will automatically display that list without the icon that you've just removed
Info
Channel: GDG Córdoba Argentina
Views: 3,030
Rating: 4.7590361 out of 5
Keywords: google, developers, group, GDG, GDG Córdoba, GDG Córdoba Argentina, tech talk, charla, en vivo, tecnología, android, paging, kotlin, android architecture components, architecture, components, android11
Id: Wa05Gq4xUmw
Channel Id: undefined
Length: 39min 15sec (2355 seconds)
Published: Fri Jul 31 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.