• This repository has been archived on 06/Sep/2023
  • Stars
    star
    169
  • Rank 224,453 (Top 5 %)
  • Language
    Kotlin
  • License
    MIT License
  • Created over 6 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Android Kotlin paged endpoints made easy

Fountain

Release License: MIT codebeat badge

A smart and simple way to work with paged endpoints. To see an example of how to use it, check out the introducing Fountain posts: part one and part two.

Atention: since all of Fountain functionalities are present in android official Paging3 library, Fountain is deprecated and we recommend using that tool.

Overview

Fountain is an Android Kotlin library conceived to make your life easier when dealing with paged endpoint services, where the paging is based on incremental page numbers (e.g. 1, 2, 3, ...). It uses the Google Android Architecture Components, mainly the Android Paging Library to make it easier to work with paged services.

The main goal of the library is to easily provide a Listing component from a common service specification. Listing provides essentially five elements to take control of the paged list:

data class Listing<T>(
    val pagedList: LiveData<PagedList<T>>,
    val networkState: LiveData<NetworkState>,
    val refreshState: LiveData<NetworkState>,
    val refresh: () -> Unit,
    val retry: () -> Unit
)
  1. pagedList: A changing data stream of type T represented as a LiveData of a PagedList.
  2. networkState: A stream that notifies network state changes, such as when a new page started loading (so you can show a spinner in the UI).
  3. refresh: A refresh function, to refresh all data.
  4. refreshState: A stream that notifies the status of the refresh request.
  5. retry: A retry function to execute if something failed.

Basically, you could manage all data streams with a Listing component, which is awesome! It's really flexible and useful to display the paged list entities and reflect the network status changes in the UI.

This library was designed to work with paged endpoints. However, it also supports working with not paged endpoints. That means that you can use all Listing features in services that return a list that's not paged.

Fountain provides two ways to generate a Listing component from paged services:

  1. Network support: Provides a Listing based on a common Retrofit service implementation. Note entities won't be saved in memory nor disk.
  2. Cache + Network support: Provides a Listing with cache support using a common Retrofit service implementation, and a DataSource for caching the data. We recommend you use Room to provide the DataSource, because it will be easier. However, you could use any other DataSource.

Fountain supports 2 types of Retrofit service adapters:

It also supports not using any of them, as you could work with a simple Retrofit call.

Download

Add library to project dependencies with JitPack.

repositories {
    maven { url "https://jitpack.io" }
}

dependencies {
    // This dependency is required only if you want to use a Retrofit service without a special adapter. 
    implementation 'com.github.xmartlabs.fountain:fountain-retrofit:0.5.0'

    // This dependency is required only if you want to use a Coroutine retrofit adapter.
    implementation 'com.github.xmartlabs.fountain:fountain-coroutines:0.5.0'

    // This dependency is required only if you want to use a RxJava2 retrofit adapter.
    implementation 'com.github.xmartlabs.fountain:fountain-rx2:0.5.0'
}

Fountain is using Kotlin 1.3, if you are using Kotlin 1.2.X, please use Fountain 0.4.0.

Despite Fountain is in experimental state, we believe the API won't receive major changes.

Usage

You can read the full documentation.

Factory constructors

There's one static factory object class for each each dependency.

  • FountainCoroutines: Used to get a Listing from a Retrofit service which uses a Coroutine adapter.
  • FountainRetrofit: Used to get a Listing from a Retrofit service without using a special adapter.
  • FountainRx: Used to get a Listing from a Retrofit service which uses a RxJava2 adapter.

Each static factory has the same constructors with different params:

Network support

Provides a Listing based on a common Retrofit service implementation. In this mode the fetched entities are volatile, they won't be saved in memory nor disk.

Network support for paged endpoints

The Listing with network support for paged endpoints can be obtained invoking createNetworkListing from the static factory class.

It requires only one argument, a NetworkDataSourceAdapter, which provides all operations that the library will use to handle the paging.

The NetworkDataSourceAdapter contains two main functions: a method to check if a page can be fetched and a property to fetch it.

interface NetworkDataSourceAdapter<PageFetcher> {
  val pageFetcher: PageFetcher

  @CheckResult
  fun canFetch(page: Int, pageSize: Int): Boolean
}

PageFetcher is a structure that provides a way to fetch a page from a service call. There is one page fetcher per library adapter, we will refer to any of them as PageFetcher throughout the documentation.

interface RetrofitPageFetcher<T : ListResponse<*>> {
  fun fetchPage(page: Int, pageSize: Int): Call<T>
}

interface CoroutinePageFetcher<T : ListResponse<*>> {
  fun fetchPage(page: Int, pageSize: Int): Deferred<T>
}

interface RxPageFetcher<T : ListResponse<*>> {
  fun fetchPage(page: Int, pageSize: Int): Single<T>
}

Network support for not paged endpoints

The Listing with network support for not paged endpoints can be obtained invoking createNetworkListing from the static factory class.

It requires only one argument, a NotPagedPageFetcher, which provides a method to fetch the data from a service source.

There is one NotPagedPageFetcher per library adapter, we will refer to any of them as NotPagedPageFetcher throughout the documentation.

interface NotPagedRetrifitPageFetcher<T : ListResponse<*>> {
  fun fetchData(): Call<T>
}

interface NotPagedCoroutinePageFetcher<T : ListResponse<*>> {
  fun fetchData(): Deferred<T>
}

interface NotPagedRxPageFetcher<T : ListResponse<*>> {
  fun fetchData(): Single<T>
}
List Responses

The library defines a common service response type which is used to fetch the pages.

interface ListResponse<T> {
  fun getElements(): List<T>
}

Additionally, there are other response types that can be used when the service provides more information in the response.

ListResponseWithEntityCount: Used when the service provides the amount of entities.

interface ListResponseWithEntityCount<T> : ListResponse<T> {
  fun getEntityCount() : Long
}

ListResponseWithPageCount: Used when the service provides the amount of pages.

interface ListResponseWithPageCount<T> : ListResponse<T> {
  fun getPageCount(): Long
}

If you use either ListResponseWithPageCount or ListResponseWithEntityCount you can convert a PageFetcher to a NetworkDataSourceAdapter. That means that if the response has the number of pages or entities you can get a NetworkDataSourceAdapter without implementing the canFetch method.

To do that Fountain provides some extensions:

fun <ServiceResponse : ListResponseWithEntityCount<*>>
    PageFetcher<ServiceResponse>.toTotalEntityCountNetworkDataSourceAdapter(firstPage: Int)
fun <ServiceResponse : ListResponseWithPageCount<*>>
    PageFetcher<ServiceResponse>.toTotalPageCountNetworkDataSourceAdapter(firstPage: Int)

Cache + Network support

Provides a Listing with cache support using a common Retrofit service implementation, and a DataSource for caching the data.

Cache + Network support for paged endpoints

The Listing with network and cache support for paged endpoints can be obtained invoking createNetworkWithCacheSupportListing from the static factory class.

It has two required components:

  1. A NetworkDataSourceAdapter<out ListResponse<NetworkValue>> to fetch all pages.
  2. A CachedDataSourceAdapter<NetworkValue, DataSourceValue> to update the DataSource. It's the interface that the library will use to take control of the DataSource.

Cache + Network support for not paged endpoints

The Listing with network and cache support for not paged endpoints can be obtained invoking createNotPagedNetworkWithCacheSupportListing from the static factory class.

It has two required components:

  1. A NotPagedPageFetcher<out ListResponse<NetworkValue>> to fetch the data.
  2. A CachedDataSourceAdapter<NetworkValue, DataSourceValue> to update the DataSource. It's the interface that the library will use to take control of the DataSource.

CachedDataSourceAdapter

interface CachedDataSourceAdapter<NetworkValue, DataSourceValue> {
  fun getDataSourceFactory(): DataSource.Factory<*, DataSourceValue>

  @WorkerThread
  fun saveEntities(response: List<NetworkValue>)

  @WorkerThread
  fun dropEntities()

  @WorkerThread
  fun runInTransaction(transaction: () -> Unit)
}

It has only four methods that you should implement:

  • getDataSourceFactory will be used to list the cached elements. The returned value is used to create the LivePagedListBuilder.
  • runInTransaction will be used to apply multiple DataSource operations in a single transaction. That means that if something fails, all operations will fail.
  • saveEntities will be invoked to save all entities into the DataSource. This will be executed in a transaction.
  • dropEntities will be used to delete all cached entities from the DataSource. This will be executed in a transaction.

Caching strategy

The pagination strategy that Fountain is using can be seen in the following image:

It starts with an initial service data request. By default the initial data requested is three pages, but this value can be changed, in the PagedList.Config, using the setInitialLoadSizeHint method. This parameter can be set in the factory constructor method. When the service data comes from the service, all data is refreshed in the DataSource using the CachedDataSourceAdapter. Note that the Listing component will notify that data changed.

After that, the Android Paging Library will require pages when the local data is running low. When a new page is required, the paging library will invoke a new service call, and will use the CachedDataSourceAdapter to save the returned data into the DataSource.

Architecture recommendations

It's strongly recommended to integrate this component in a MVVM architecture combined with the Repository Pattern. The Listing component should be provided by the repository. The ViewModel, can use the different Listing elements, provided by the repository, to show the data and the network changes in the UI.

You can take a look at the example project to see how everything comes together.

Getting involved

  • If you want to contribute please feel free to submit pull requests.
  • If you have a feature request please open an issue.
  • If you found a bug check older issues before submitting a new one.
  • If you need help or would like to ask a general question, use StackOverflow. (Tag fountain).

Before contributing, please check the CONTRIBUTING file.

Changelog

The changelog for this project can be found in the CHANGELOG file.

About

Made with ❤️ by XMARTLABS

More Repositories

1

Eureka

Elegant iOS form builder in Swift
Swift
11,705
star
2

XLPagerTabStrip

Android PagerTabStrip for iOS.
Swift
6,880
star
3

XLForm

XLForm is the most flexible and powerful iOS library to create dynamic table-view forms. Fully compatible with Swift & Obj-C.
Objective-C
5,790
star
4

XLActionController

Fully customizable and extensible action sheet controller written in Swift
Swift
3,326
star
5

Bender

Easily craft fast Neural Networks on iOS! Use TensorFlow models. Metal under the hood.
Swift
1,795
star
6

PagerTabStripView

🚀 Elegant Pager View fully written in pure SwiftUI.
Swift
722
star
7

Xniffer

A swift network profiler built on top of URLSession.
Swift
502
star
8

XLRemoteImageView

UIImageView that shows a progress indicator while the image is loading from server. It makes use of AFNetworking. It looks like the Instagram loading indicator.
Objective-C
346
star
9

XLData

Elegant and concise way to load and show data sets into table and collection view. It supports AFNetworking, Core Data and memory data stores.
Objective-C
165
star
10

XLSlidingContainer

XLSlidingContainer is a custom container controller that embeds two independent view controllers allowing to easily maximize any of them using gestures.
Swift
149
star
11

android-snapshot-publisher

Gradle plugin to deploy Android Snapshot Versions
Kotlin
145
star
12

Swift-Project-Template

Script to easily create an iOS project base code!
Swift
144
star
13

Swift-Framework-Template

Swift script to easily create Swift frameworks!
Swift
143
star
14

react-native-line

Line SDK wrapper for React Native 🚀
TypeScript
119
star
15

Ecno

Ecno is a task state manager built on top of UserDefaults in pure Swift 4.
Swift
102
star
16

XLSwiftKit

Helpers and extensions for Swift
Swift
101
star
17

XLMediaZoom

UI controls to view an image or reproduce a video in fullscreen like Instagram does.
Swift
92
star
18

XLMailBoxContainer

Custom container view controller ala MailBox app.
Objective-C
90
star
19

gong

Xmartlabs' Android Base Project Template
Kotlin
89
star
20

cordova-plugin-market

Cordova Plugin that allows you to access native Marketplace app (aka Google Play, App Store) from your app
Java
87
star
21

stock

Dart package for Async Data Loading and Caching. Combine local (DB, cache) and network data simply and safely.
Dart
74
star
22

Opera

Protocol-Oriented Network abstraction layer written in Swift.
Swift
74
star
23

Ahoy

A lightweight swift library to build onboarding experiences.
Swift
52
star
24

bigbang

Android base project used by Xmartlabs team
Kotlin
50
star
25

MetalPerformanceShadersProxy

A proxy for MetalPerformanceShaders which takes to a stub on a simulator and to the real implementation on iOS devices.
Objective-C
45
star
26

Swift-Style-Guide

Swift language style guide & coding conventions followed by Xmartlabs.
44
star
27

RxSimpleNoSQL

Reactive extensions for SimpleNoSQL
Java
37
star
28

docker-jenkins-android

Jenkins docker image for Android development
36
star
29

docker-htpasswd

Docker image to create a htpasswd file
32
star
30

spoter-embeddings

Create embeddings from sign pose videos using Transformers
Python
30
star
31

TypedNavigation

A lightweight library to help you navigate in compose with well typed functions.
Kotlin
23
star
32

XLMapChat

A chat application running on Node.js, using Socket.IO, GMaps, and more...
JavaScript
22
star
33

flutter-template

Xmartlabs' Flutter Base Project
Dart
17
star
34

XLDataLoader

Objective-C
16
star
35

tf_tabular

Easily build TensorFlow models on tabular data
Python
16
star
36

dreamsnap

Real life through the eyes of an artist
CSS
15
star
37

bigbang-template

Android template used by Xmartlabs team
Kotlin
14
star
38

blog

Xmartlabs Blog
CSS
14
star
39

MLKitTest

Source code related to a blog post about ML Kit
Swift
13
star
40

benderthon

Set of utilities to work easier with Bender.
Python
13
star
41

XLiOSKit

Objective-C
13
star
42

python-template

Python
9
star
43

react-template-xmartlabs

This is an internal private project - aims to be at some point in the future our React base project
TypeScript
9
star
44

gpgpu-comparison

9
star
45

XmartRecyclerView

A smart, simple and fast RecyclerView library
Java
8
star
46

jared-landing

Landing page for Jared Bot.
HTML
8
star
47

Fastlane-CI-Files

Fastlane CI files
Ruby
8
star
48

fluttips

Flutter trips and tricks
JavaScript
8
star
49

Android-Style-Guide

Style guide for Android by Xmartlabs
7
star
50

XLMaterialCalendarView

MaterialCalendarView powered with reactive bindings and with the Java 8 Time API!
Java
6
star
51

rnx-cli

TypeScript
6
star
52

docker-android

Docker image for Android development.
6
star
53

gh-top-repos-users

Download the contributors of the top repos.
Python
5
star
54

BuildSlackNotifier

Jenkins plugin to send Android build results through a slack channel using incoming webhooks
Java
4
star
55

javascript-plugin

Source Code of blog Making a JS widget: a full-stack approach
Ruby
4
star
56

AndroidSwissKnife

Kotlin
3
star
57

projecthub-landing

ProjectHub lets you manage your GitHub Projects on the fly, from your mobile phone.
HTML
3
star
58

gh2s3

Download GitHub Archive data and upload it to an Amazon S3 bucket.
Python
3
star
59

xmartchat

Dart
3
star
60

pycon-es-workshop

Python
2
star
61

xl-blog

Gatsby XL's Blogpost
JavaScript
2
star
62

node-template

Base template for starting a new Node project
TypeScript
2
star
63

mPOS-SDK-iOS

Objective-C
1
star
64

terraform

HCL
1
star
65

FastlaneDemo

Demo project to show a basic fastlane configuration
Swift
1
star
66

xl-school-automation-web

This is the repository for web automation training for XL
Java
1
star
67

workshop-microservicios

Python
1
star
68

fountain-docs

Fountain documentation
1
star
69

client-side-widget-template

JavaScript templates for a client-side widget
HTML
1
star
70

rn-lightbox

JavaScript
1
star
71

malaria-detector

Jupyter Notebook
1
star
72

SQLiteDSL

1
star
73

terraform-basic-infra

HCL
1
star
74

docker-pcl-cmake

Docker image containing PCL and CMake.
1
star
75

cocoapods-specs

Ruby
1
star
76

simon-ai

This is the repository for the XL Says initiative
Dart
1
star