I recently learned about the Paging library – part of Android Jetpack. Although there are some resources on how to implement this library in an application, I have faced a lot of problems and have to learn more about it. So I think I will write about 7 basic steps to deploy Paging library in Android apps.
The Paging library makes it easier to load paging data in your application. The Paging library also supports large-bound, non-bound data lists (eg, continuously updating feeds). The paging library is based on the idea of sending the list of data to the UI in the livedata form of the list and is observed by RecyclerView.Adapter.
I have chosen to build a news delivery application to test the Paging library. Let’s go back to the main topic, 7 steps to install the library.
I. Add Paging library into the application
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | apply plugin: 'com.android.application' android { compileSdkVersion 27 defaultConfig { applicationId "com.an.paginglibrary.sample" minSdkVersion 14 targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } /* * This is just to enable Java 8 in the app */ compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } /* * I prefer using data binding so we need to enable it first */ android { dataBinding { enabled = true } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:recyclerview-v7:27.1.1' implementation 'com.android.support:support-v4:27.1.1' implementation 'com.android.support:cardview-v7:27.1.1' implementation 'com.android.support:design:27.1.1' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' /* * Step 1: Add the paging library */ implementation 'android.arch.paging:runtime:1.0.0' /* * Step 2: Adding ViewModel and Lifecycle */ implementation 'android.arch.lifecycle:extensions:1.1.1' /* * Step 3: Adding rxJava to the app */ implementation 'io.reactivex.rxjava2:rxjava:2.1.9' implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' /* * Step 4: Adding retrofit to the app */ implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1' /* * Step 5: We would be needing an image loading library. * So we are going to use Picasso */ implementation 'com.squareup.picasso:picasso:2.71828' } |
II. Install Retrofit to get data from api
Create an interface ** RestApi.java **:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">RestApi</span> <span class="token punctuation">{</span> <span class="token comment">/* * We would be using the below url: * https://newsapi.org/v2/everything?q=movies&apiKey=079dac74a5f94ebdb990ecf61c8854b7&pageSize=20&page=2 * The url has four query parameters. * We would be changing the pageSize and the page */</span> <span class="token annotation punctuation">@GET</span> <span class="token punctuation">(</span> <span class="token string">"/v2/everything"</span> <span class="token punctuation">)</span> <span class="token class-name">Call</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> <span class="token function">fetchFeed</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@Query</span> <span class="token punctuation">(</span> <span class="token string">"q"</span> <span class="token punctuation">)</span> <span class="token class-name">String</span> q <span class="token punctuation">,</span> <span class="token annotation punctuation">@Query</span> <span class="token punctuation">(</span> <span class="token string">"apiKey"</span> <span class="token punctuation">)</span> <span class="token class-name">String</span> apiKey <span class="token punctuation">,</span> <span class="token annotation punctuation">@Query</span> <span class="token punctuation">(</span> <span class="token string">"page"</span> <span class="token punctuation">)</span> <span class="token keyword">long</span> page <span class="token punctuation">,</span> <span class="token annotation punctuation">@Query</span> <span class="token punctuation">(</span> <span class="token string">"pageSize"</span> <span class="token punctuation">)</span> <span class="token keyword">int</span> pageSize <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Then create class RestApiFactory.java :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">String</span> BASE_URL <span class="token operator">=</span> <span class="token string">"https://newsapi.org"</span> <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">RestApi</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">HttpLoggingInterceptor</span> logging <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HttpLoggingInterceptor</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> logging <span class="token punctuation">.</span> <span class="token function">setLevel</span> <span class="token punctuation">(</span> <span class="token class-name">HttpLoggingInterceptor</span> <span class="token punctuation">.</span> <span class="token class-name">Level</span> <span class="token punctuation">.</span> BODY <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">OkHttpClient</span> <span class="token punctuation">.</span> <span class="token class-name">Builder</span> httpClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">OkHttpClient</span> <span class="token punctuation">.</span> <span class="token class-name">Builder</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> httpClient <span class="token punctuation">.</span> <span class="token function">addInterceptor</span> <span class="token punctuation">(</span> logging <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">Retrofit</span> retrofit <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Retrofit</span> <span class="token punctuation">.</span> <span class="token class-name">Builder</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">baseUrl</span> <span class="token punctuation">(</span> BASE_URL <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">addConverterFactory</span> <span class="token punctuation">(</span> <span class="token class-name">GsonConverterFactory</span> <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">addCallAdapterFactory</span> <span class="token punctuation">(</span> <span class="token class-name">RxJava2CallAdapterFactory</span> <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">client</span> <span class="token punctuation">(</span> httpClient <span class="token punctuation">.</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> retrofit <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token class-name">RestApi</span> <span class="token punctuation">.</span> <span class="token keyword">class</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
III. Install DataSource
DataSource – This is the base class to load data, used in the list paging. DataSource can be implemented using any of the following 3 classes:
PageKeyedDataSource : We can use this class if we need to load data based on the number of pages in the DataSource. For example we pass the page number as a query parameter in the request, the page number will increase sequentially until all pages are retrieved and displayed.
ItemKeyedDataSource : The first step is to define the key, the purpose is to load data on the next page based on that key. For example, data class User, the id field will usually have the key is userId. The size of the list is unknown, and retrieving the next data usually depends on the most recently known id. So if we get data for items 1 through 10 in the first result, the ItemKeyedDataSource will automatically fetch the next data from 11-20.
PositionalDataSource : This class will be useful for list supplies of fixed size, retrievable in any arbitrary position and size.
In this article, I will use PageKeyedDataSource. Take a look at the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FeedDataSource</span> <span class="token keyword">extends</span> <span class="token class-name">PageKeyedDataSource</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Long</span> <span class="token punctuation">,</span> <span class="token class-name">Article</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> TAG <span class="token operator">=</span> <span class="token class-name">FeedDataSource</span> <span class="token punctuation">.</span> <span class="token keyword">class</span> <span class="token punctuation">.</span> <span class="token function">getSimpleName</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">/* * Step 1: Initialize the restApiFactory. * The networkState and initialLoading variables * are for updating the UI when data is being fetched * by displaying a progress bar */</span> <span class="token keyword">private</span> <span class="token class-name">RestApiFactory</span> restApiFactory <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">MutableLiveData</span> networkState <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">MutableLiveData</span> initialLoading <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">FeedDataSource</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> restApiFactory <span class="token operator">=</span> <span class="token class-name">RestApiFactory</span> <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MutableLiveData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> initialLoading <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MutableLiveData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">MutableLiveData</span> <span class="token function">getNetworkState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> networkState <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">MutableLiveData</span> <span class="token function">getInitialLoading</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> initialLoading <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* * Step 2: This method is responsible to load the data initially * when app screen is launched for the first time. * We are fetching the first page data from the api * and passing it via the callback method to the UI. */</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">loadInitial</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">LoadInitialParams</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Long</span> <span class="token punctuation">></span></span> params <span class="token punctuation">,</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">LoadInitialCallback</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Long</span> <span class="token punctuation">,</span> <span class="token class-name">Article</span> <span class="token punctuation">></span></span> callback <span class="token punctuation">)</span> <span class="token punctuation">{</span> initialLoading <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> LOADING <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> LOADING <span class="token punctuation">)</span> <span class="token punctuation">;</span> appController <span class="token punctuation">.</span> <span class="token function">getRestApi</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">fetchFeed</span> <span class="token punctuation">(</span> QUERY <span class="token punctuation">,</span> API_KEY <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">,</span> params <span class="token punctuation">.</span> requestedLoadSize <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">enqueue</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">Callback</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onResponse</span> <span class="token punctuation">(</span> <span class="token class-name">Call</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> call <span class="token punctuation">,</span> <span class="token class-name">Response</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> response <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> response <span class="token punctuation">.</span> <span class="token function">isSuccessful</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> callback <span class="token punctuation">.</span> <span class="token function">onResult</span> <span class="token punctuation">(</span> response <span class="token punctuation">.</span> <span class="token function">body</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">getArticles</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> <span class="token number">2l</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> initialLoading <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> LOADED <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> LOADED <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> initialLoading <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> <span class="token class-name">Status</span> <span class="token punctuation">.</span> FAILED <span class="token punctuation">,</span> response <span class="token punctuation">.</span> <span class="token function">message</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> <span class="token class-name">Status</span> <span class="token punctuation">.</span> FAILED <span class="token punctuation">,</span> response <span class="token punctuation">.</span> <span class="token function">message</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onFailure</span> <span class="token punctuation">(</span> <span class="token class-name">Call</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> call <span class="token punctuation">,</span> <span class="token class-name">Throwable</span> t <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">String</span> errorMessage <span class="token operator">=</span> t <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token string">"unknown error"</span> <span class="token operator">:</span> t <span class="token punctuation">.</span> <span class="token function">getMessage</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> <span class="token class-name">Status</span> <span class="token punctuation">.</span> FAILED <span class="token punctuation">,</span> errorMessage <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">loadBefore</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">LoadParams</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Long</span> <span class="token punctuation">></span></span> params <span class="token punctuation">,</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">LoadCallback</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Long</span> <span class="token punctuation">,</span> <span class="token class-name">Article</span> <span class="token punctuation">></span></span> callback <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token comment">/* * Step 3: This method it is responsible for the subsequent call to load the data page wise. * This method is executed in the background thread * We are fetching the next page data from the api * and passing it via the callback method to the UI. * The "params.key" variable will have the updated value. */</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">loadAfter</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">LoadParams</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Long</span> <span class="token punctuation">></span></span> params <span class="token punctuation">,</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">LoadCallback</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Long</span> <span class="token punctuation">,</span> <span class="token class-name">Article</span> <span class="token punctuation">></span></span> callback <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Log</span> <span class="token punctuation">.</span> <span class="token function">i</span> <span class="token punctuation">(</span> TAG <span class="token punctuation">,</span> <span class="token string">"Loading Rang "</span> <span class="token operator">+</span> params <span class="token punctuation">.</span> key <span class="token operator">+</span> <span class="token string">" Count "</span> <span class="token operator">+</span> params <span class="token punctuation">.</span> requestedLoadSize <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> LOADING <span class="token punctuation">)</span> <span class="token punctuation">;</span> appController <span class="token punctuation">.</span> <span class="token function">getRestApi</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">fetchFeed</span> <span class="token punctuation">(</span> QUERY <span class="token punctuation">,</span> API_KEY <span class="token punctuation">,</span> params <span class="token punctuation">.</span> key <span class="token punctuation">,</span> params <span class="token punctuation">.</span> requestedLoadSize <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">enqueue</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">Callback</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onResponse</span> <span class="token punctuation">(</span> <span class="token class-name">Call</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> call <span class="token punctuation">,</span> <span class="token class-name">Response</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> response <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* * If the request is successful, then we will update the callback * with the latest feed items and * "params.key+1" -> set the next key for the next iteration. */</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> response <span class="token punctuation">.</span> <span class="token function">isSuccessful</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">long</span> nextKey <span class="token operator">=</span> <span class="token punctuation">(</span> params <span class="token punctuation">.</span> key <span class="token operator">==</span> response <span class="token punctuation">.</span> <span class="token function">body</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">getTotalResults</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token keyword">null</span> <span class="token operator">:</span> params <span class="token punctuation">.</span> key <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">;</span> callback <span class="token punctuation">.</span> <span class="token function">onResult</span> <span class="token punctuation">(</span> response <span class="token punctuation">.</span> <span class="token function">body</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">getArticles</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> nextKey <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> LOADED <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> <span class="token class-name">Status</span> <span class="token punctuation">.</span> FAILED <span class="token punctuation">,</span> response <span class="token punctuation">.</span> <span class="token function">message</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onFailure</span> <span class="token punctuation">(</span> <span class="token class-name">Call</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Feed</span> <span class="token punctuation">></span></span> call <span class="token punctuation">,</span> <span class="token class-name">Throwable</span> t <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">String</span> errorMessage <span class="token operator">=</span> t <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token string">"unknown error"</span> <span class="token operator">:</span> t <span class="token punctuation">.</span> <span class="token function">getMessage</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> <span class="token class-name">Status</span> <span class="token punctuation">.</span> FAILED <span class="token punctuation">,</span> errorMessage <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
IV. Install DataSourceFactory
DataSourceFactory is responsible for accessing data using the DataSource ‘s config and the PagedList that I will create later in this article in the ViewModel class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FeedDataFactory</span> <span class="token keyword">extends</span> <span class="token class-name">DataSource</span> <span class="token punctuation">.</span> <span class="token class-name">Factory</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token class-name">MutableLiveData</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">FeedDataSource</span> <span class="token punctuation">></span></span> mutableLiveData <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">FeedDataSource</span> feedDataSource <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">FeedDataFactory</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> mutableLiveData <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MutableLiveData</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">FeedDataSource</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">DataSource</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> feedDataSource <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FeedDataSource</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> mutableLiveData <span class="token punctuation">.</span> <span class="token function">postValue</span> <span class="token punctuation">(</span> feedDataSource <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> feedDataSource <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">MutableLiveData</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">FeedDataSource</span> <span class="token punctuation">></span></span> <span class="token function">getMutableLiveData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> mutableLiveData <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
V. ViewModel class implementation
ViewModel will be responsible for creating PagedList along with its configs and sending it to Activity so that Activity can observe data as data changes and pass it to adapter.
Surely everyone is wondering what is PagedList ? The PagedList is a list that contains your data items and calls DataSource to load the elements. It usually consists of a work done in the background (loading data) and a job done in the foreground (updating the UI based on the downloaded data).
For example, let’s say there is some data that we add to the DataSource in the background thread. The DataSource invalidates the PagedList and updates the value. Then on the main thread, the PagedList will notify the observe elements it has new values. Now the PagedListAdapter knows about the new value.
PageList has 4 parameters that we need to pay attention to:
a. setEnablePlaceHolder (boolean enablePlaceholders) b. setInitialLoadSizeHint (int initialLoadSizeHint) c. setPageSize (int pageSize) d. setPageSize (int pageSize)
Below is the ViewModel class of the project:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FeedViewModel</span> <span class="token keyword">extends</span> <span class="token class-name">ViewModel</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token class-name">Executor</span> executor <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">LiveData</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">></span></span> networkState <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">LiveData</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">PagedList</span> <span class="token punctuation"><</span> <span class="token class-name">Article</span> <span class="token punctuation">></span> <span class="token punctuation">></span></span> articleLiveData <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">FeedViewModel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">init</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* * Step 1: We are initializing an Executor class * Step 2: We are getting an instance of the DataSourceFactory class * Step 3: We are initializing the network state liveData as well. * This will update the UI on the network changes that take place * For instance, when the data is getting fetched, we would need * to display a loader and when data fetching is completed, we * should hide the loader. * Step 4: We need to configure the PagedList.Config. * Step 5: We are initializing the pageList using the config we created * in Step 4 and the DatasourceFactory we created from Step 2 * and the executor we initialized from Step 1. */</span> <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">init</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> executor <span class="token operator">=</span> <span class="token class-name">Executors</span> <span class="token punctuation">.</span> <span class="token function">newFixedThreadPool</span> <span class="token punctuation">(</span> <span class="token number">5</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">FeedDataFactory</span> feedDataFactory <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FeedDataFactory</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> networkState <span class="token operator">=</span> <span class="token class-name">Transformations</span> <span class="token punctuation">.</span> <span class="token function">switchMap</span> <span class="token punctuation">(</span> feedDataFactory <span class="token punctuation">.</span> <span class="token function">getMutableLiveData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> dataSource <span class="token operator">-></span> dataSource <span class="token punctuation">.</span> <span class="token function">getNetworkState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">PagedList</span> <span class="token punctuation">.</span> <span class="token class-name">Config</span> pagedListConfig <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">PagedList</span> <span class="token punctuation">.</span> <span class="token class-name">Config</span> <span class="token punctuation">.</span> <span class="token class-name">Builder</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setEnablePlaceholders</span> <span class="token punctuation">(</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setInitialLoadSizeHint</span> <span class="token punctuation">(</span> <span class="token number">10</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setPageSize</span> <span class="token punctuation">(</span> <span class="token number">20</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> articleLiveData <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">LivePagedListBuilder</span> <span class="token punctuation">(</span> feedDataFactory <span class="token punctuation">,</span> pagedListConfig <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setFetchExecutor</span> <span class="token punctuation">(</span> executor <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* * Getter method for the network state */</span> <span class="token keyword">public</span> <span class="token class-name">LiveData</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">></span></span> <span class="token function">getNetworkState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> networkState <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* * Getter method for the pageList */</span> <span class="token keyword">public</span> <span class="token class-name">LiveData</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">PagedList</span> <span class="token punctuation"><</span> <span class="token class-name">Article</span> <span class="token punctuation">></span> <span class="token punctuation">></span></span> <span class="token function">getArticleLiveData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> articleLiveData <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
BECAUSE. Install PagedListAdapter
PagedListAdapter is an implementation of RecyclerView. Adapter takes data from PagedList, it uses DiffUtil as parameter to calculate the difference of data and do all the updates for you. DiffUtil is defined in the Model Class in this case:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Article</span> <span class="token keyword">implements</span> <span class="token class-name">Parcelable</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">DiffUtil</span> <span class="token punctuation">.</span> <span class="token class-name">ItemCallback</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Article</span> <span class="token punctuation">></span></span> DIFF_CALLBACK <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DiffUtil</span> <span class="token punctuation">.</span> <span class="token class-name">ItemCallback</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Article</span> <span class="token punctuation">></span></span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">areItemsTheSame</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">Article</span> oldItem <span class="token punctuation">,</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">Article</span> newItem <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> oldItem <span class="token punctuation">.</span> id <span class="token operator">==</span> newItem <span class="token punctuation">.</span> id <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">areContentsTheSame</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">Article</span> oldItem <span class="token punctuation">,</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">Article</span> newItem <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> oldItem <span class="token punctuation">.</span> <span class="token function">equals</span> <span class="token punctuation">(</span> newItem <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">equals</span> <span class="token punctuation">(</span> <span class="token class-name">Object</span> obj <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> obj <span class="token operator">==</span> <span class="token keyword">this</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token class-name">Article</span> article <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token class-name">Article</span> <span class="token punctuation">)</span> obj <span class="token punctuation">;</span> <span class="token keyword">return</span> article <span class="token punctuation">.</span> id <span class="token operator">==</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> id <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Class PagedListAdapter :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FeedListAdapter</span> <span class="token keyword">extends</span> <span class="token class-name">PagedListAdapter</span> <span class="token generics"><span class="token punctuation"><</span> <span class="token class-name">Article</span> <span class="token punctuation">,</span> <span class="token class-name">RecyclerView</span> <span class="token punctuation">.</span> <span class="token class-name">ViewHolder</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token comment">/* * There are two layout types we define * in this adapter: * 1. progrss view * 2. data view */</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> TYPE_PROGRESS <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> TYPE_ITEM <span class="token operator">=</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">Context</span> context <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">NetworkState</span> networkState <span class="token punctuation">;</span> <span class="token comment">/* * The DiffUtil is defined in the constructor */</span> <span class="token keyword">public</span> <span class="token class-name">FeedListAdapter</span> <span class="token punctuation">(</span> <span class="token class-name">Context</span> context <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">(</span> <span class="token class-name">Article</span> <span class="token punctuation">.</span> DIFF_CALLBACK <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> context <span class="token operator">=</span> context <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/* * Default method of RecyclerView.Adapter */</span> <span class="token annotation punctuation">@NonNull</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">RecyclerView</span> <span class="token punctuation">.</span> <span class="token class-name">ViewHolder</span> <span class="token function">onCreateViewHolder</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">ViewGroup</span> parent <span class="token punctuation">,</span> <span class="token keyword">int</span> viewType <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">LayoutInflater</span> layoutInflater <span class="token operator">=</span> <span class="token class-name">LayoutInflater</span> <span class="token punctuation">.</span> <span class="token function">from</span> <span class="token punctuation">(</span> parent <span class="token punctuation">.</span> <span class="token function">getContext</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> viewType <span class="token operator">==</span> TYPE_PROGRESS <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NetworkItemBinding</span> headerBinding <span class="token operator">=</span> <span class="token class-name">NetworkItemBinding</span> <span class="token punctuation">.</span> <span class="token function">inflate</span> <span class="token punctuation">(</span> layoutInflater <span class="token punctuation">,</span> parent <span class="token punctuation">,</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">NetworkStateItemViewHolder</span> viewHolder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">NetworkStateItemViewHolder</span> <span class="token punctuation">(</span> headerBinding <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> viewHolder <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token class-name">FeedItemBinding</span> itemBinding <span class="token operator">=</span> <span class="token class-name">FeedItemBinding</span> <span class="token punctuation">.</span> <span class="token function">inflate</span> <span class="token punctuation">(</span> layoutInflater <span class="token punctuation">,</span> parent <span class="token punctuation">,</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">ArticleItemViewHolder</span> viewHolder <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArticleItemViewHolder</span> <span class="token punctuation">(</span> itemBinding <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> viewHolder <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">/* * Default method of RecyclerView.Adapter */</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onBindViewHolder</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">RecyclerView</span> <span class="token punctuation">.</span> <span class="token class-name">ViewHolder</span> holder <span class="token punctuation">,</span> <span class="token keyword">int</span> position <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> holder <span class="token keyword">instanceof</span> <span class="token class-name">ArticleItemViewHolder</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token class-name">ArticleItemViewHolder</span> <span class="token punctuation">)</span> holder <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">bindTo</span> <span class="token punctuation">(</span> <span class="token function">getItem</span> <span class="token punctuation">(</span> position <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkStateItemViewHolder</span> <span class="token punctuation">)</span> holder <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">bindView</span> <span class="token punctuation">(</span> networkState <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">/* * Default method of RecyclerView.Adapter */</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getItemViewType</span> <span class="token punctuation">(</span> <span class="token keyword">int</span> position <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token function">hasExtraRow</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">&&</span> position <span class="token operator">==</span> <span class="token function">getItemCount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> TYPE_PROGRESS <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> TYPE_ITEM <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">hasExtraRow</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> networkState <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> networkState <span class="token operator">!=</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> LOADED <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token boolean">false</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setNetworkState</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> newNetworkState <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">NetworkState</span> previousState <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> networkState <span class="token punctuation">;</span> <span class="token keyword">boolean</span> previousExtraRow <span class="token operator">=</span> <span class="token function">hasExtraRow</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> networkState <span class="token operator">=</span> newNetworkState <span class="token punctuation">;</span> <span class="token keyword">boolean</span> newExtraRow <span class="token operator">=</span> <span class="token function">hasExtraRow</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> previousExtraRow <span class="token operator">!=</span> newExtraRow <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> previousExtraRow <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">notifyItemRemoved</span> <span class="token punctuation">(</span> <span class="token function">getItemCount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">notifyItemInserted</span> <span class="token punctuation">(</span> <span class="token function">getItemCount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> newExtraRow <span class="token operator">&&</span> previousState <span class="token operator">!=</span> newNetworkState <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">notifyItemChanged</span> <span class="token punctuation">(</span> <span class="token function">getItemCount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">/* * We define A custom ViewHolder for the list item */</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ArticleItemViewHolder</span> <span class="token keyword">extends</span> <span class="token class-name">RecyclerView</span> <span class="token punctuation">.</span> <span class="token class-name">ViewHolder</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token class-name">FeedItemBinding</span> binding <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">ArticleItemViewHolder</span> <span class="token punctuation">(</span> <span class="token class-name">FeedItemBinding</span> binding <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">(</span> binding <span class="token punctuation">.</span> <span class="token function">getRoot</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> binding <span class="token operator">=</span> binding <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">bindTo</span> <span class="token punctuation">(</span> <span class="token class-name">Article</span> article <span class="token punctuation">)</span> <span class="token punctuation">{</span> binding <span class="token punctuation">.</span> itemImage <span class="token punctuation">.</span> <span class="token function">setVisibility</span> <span class="token punctuation">(</span> <span class="token class-name">View</span> <span class="token punctuation">.</span> VISIBLE <span class="token punctuation">)</span> <span class="token punctuation">;</span> binding <span class="token punctuation">.</span> itemDesc <span class="token punctuation">.</span> <span class="token function">setVisibility</span> <span class="token punctuation">(</span> <span class="token class-name">View</span> <span class="token punctuation">.</span> VISIBLE <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">String</span> author <span class="token operator">=</span> article <span class="token punctuation">.</span> <span class="token function">getAuthor</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> article <span class="token punctuation">.</span> <span class="token function">getAuthor</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">isEmpty</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">?</span> context <span class="token punctuation">.</span> <span class="token function">getString</span> <span class="token punctuation">(</span> <span class="token class-name">R</span> <span class="token punctuation">.</span> string <span class="token punctuation">.</span> author_name <span class="token punctuation">)</span> <span class="token operator">:</span> article <span class="token punctuation">.</span> <span class="token function">getAuthor</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">String</span> titleString <span class="token operator">=</span> <span class="token class-name">String</span> <span class="token punctuation">.</span> <span class="token function">format</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">getString</span> <span class="token punctuation">(</span> <span class="token class-name">R</span> <span class="token punctuation">.</span> string <span class="token punctuation">.</span> item_title <span class="token punctuation">)</span> <span class="token punctuation">,</span> author <span class="token punctuation">,</span> article <span class="token punctuation">.</span> <span class="token function">getTitle</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">SpannableString</span> spannableString <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SpannableString</span> <span class="token punctuation">(</span> titleString <span class="token punctuation">)</span> <span class="token punctuation">;</span> spannableString <span class="token punctuation">.</span> <span class="token function">setSpan</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">ForegroundColorSpan</span> <span class="token punctuation">(</span> <span class="token class-name">ContextCompat</span> <span class="token punctuation">.</span> <span class="token function">getColor</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">getApplicationContext</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token class-name">R</span> <span class="token punctuation">.</span> color <span class="token punctuation">.</span> secondary_text <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> titleString <span class="token punctuation">.</span> <span class="token function">lastIndexOf</span> <span class="token punctuation">(</span> author <span class="token punctuation">)</span> <span class="token operator">+</span> author <span class="token punctuation">.</span> <span class="token function">length</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">,</span> titleString <span class="token punctuation">.</span> <span class="token function">lastIndexOf</span> <span class="token punctuation">(</span> article <span class="token punctuation">.</span> <span class="token function">getTitle</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token class-name">Spannable</span> <span class="token punctuation">.</span> SPAN_EXCLUSIVE_EXCLUSIVE <span class="token punctuation">)</span> <span class="token punctuation">;</span> binding <span class="token punctuation">.</span> itemTitle <span class="token punctuation">.</span> <span class="token function">setText</span> <span class="token punctuation">(</span> spannableString <span class="token punctuation">)</span> <span class="token punctuation">;</span> binding <span class="token punctuation">.</span> itemTime <span class="token punctuation">.</span> <span class="token function">setText</span> <span class="token punctuation">(</span> <span class="token class-name">String</span> <span class="token punctuation">.</span> <span class="token function">format</span> <span class="token punctuation">(</span> context <span class="token punctuation">.</span> <span class="token function">getString</span> <span class="token punctuation">(</span> <span class="token class-name">R</span> <span class="token punctuation">.</span> string <span class="token punctuation">.</span> item_date <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token class-name">AppUtils</span> <span class="token punctuation">.</span> <span class="token function">getDate</span> <span class="token punctuation">(</span> article <span class="token punctuation">.</span> <span class="token function">getPublishedAt</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token class-name">AppUtils</span> <span class="token punctuation">.</span> <span class="token function">getTime</span> <span class="token punctuation">(</span> article <span class="token punctuation">.</span> <span class="token function">getPublishedAt</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> binding <span class="token punctuation">.</span> itemDesc <span class="token punctuation">.</span> <span class="token function">setText</span> <span class="token punctuation">(</span> article <span class="token punctuation">.</span> <span class="token function">getDescription</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">Picasso</span> <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">load</span> <span class="token punctuation">(</span> article <span class="token punctuation">.</span> <span class="token function">getUrlToImage</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">resize</span> <span class="token punctuation">(</span> <span class="token number">250</span> <span class="token punctuation">,</span> <span class="token number">200</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">into</span> <span class="token punctuation">(</span> binding <span class="token punctuation">.</span> itemImage <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">/* * We define A custom ViewHolder for the progressView */</span> <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">NetworkStateItemViewHolder</span> <span class="token keyword">extends</span> <span class="token class-name">RecyclerView</span> <span class="token punctuation">.</span> <span class="token class-name">ViewHolder</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token class-name">NetworkItemBinding</span> binding <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">NetworkStateItemViewHolder</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkItemBinding</span> binding <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">(</span> binding <span class="token punctuation">.</span> <span class="token function">getRoot</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> binding <span class="token operator">=</span> binding <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">bindView</span> <span class="token punctuation">(</span> <span class="token class-name">NetworkState</span> networkState <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> networkState <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> networkState <span class="token punctuation">.</span> <span class="token function">getStatus</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> <span class="token class-name">Status</span> <span class="token punctuation">.</span> RUNNING <span class="token punctuation">)</span> <span class="token punctuation">{</span> binding <span class="token punctuation">.</span> progressBar <span class="token punctuation">.</span> <span class="token function">setVisibility</span> <span class="token punctuation">(</span> <span class="token class-name">View</span> <span class="token punctuation">.</span> VISIBLE <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> binding <span class="token punctuation">.</span> progressBar <span class="token punctuation">.</span> <span class="token function">setVisibility</span> <span class="token punctuation">(</span> <span class="token class-name">View</span> <span class="token punctuation">.</span> GONE <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> networkState <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> networkState <span class="token punctuation">.</span> <span class="token function">getStatus</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token class-name">NetworkState</span> <span class="token punctuation">.</span> <span class="token class-name">Status</span> <span class="token punctuation">.</span> FAILED <span class="token punctuation">)</span> <span class="token punctuation">{</span> binding <span class="token punctuation">.</span> errorMsg <span class="token punctuation">.</span> <span class="token function">setVisibility</span> <span class="token punctuation">(</span> <span class="token class-name">View</span> <span class="token punctuation">.</span> VISIBLE <span class="token punctuation">)</span> <span class="token punctuation">;</span> binding <span class="token punctuation">.</span> errorMsg <span class="token punctuation">.</span> <span class="token function">setText</span> <span class="token punctuation">(</span> networkState <span class="token punctuation">.</span> <span class="token function">getMsg</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> binding <span class="token punctuation">.</span> errorMsg <span class="token punctuation">.</span> <span class="token function">setVisibility</span> <span class="token punctuation">(</span> <span class="token class-name">View</span> <span class="token punctuation">.</span> GONE <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
VII. Activity settings
The last step is to install the Activity class with ViewModel , RecyclerView , PagedListAdapter :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FeedActivity</span> <span class="token keyword">extends</span> <span class="token class-name">AppCompatActivity</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token class-name">FeedListAdapter</span> adapter <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">FeedViewModel</span> feedViewModel <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token class-name">FeedActivityBinding</span> binding <span class="token punctuation">;</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">Bundle</span> savedInstanceState <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span> <span class="token punctuation">.</span> <span class="token function">onCreate</span> <span class="token punctuation">(</span> savedInstanceState <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">/* * Step 1: Using DataBinding, we setup the layout for the activity * * */</span> binding <span class="token operator">=</span> <span class="token class-name">DataBindingUtil</span> <span class="token punctuation">.</span> <span class="token function">setContentView</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> <span class="token class-name">R</span> <span class="token punctuation">.</span> layout <span class="token punctuation">.</span> activity_main <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">/* * Step 2: Initialize the ViewModel * * */</span> feedViewModel <span class="token operator">=</span> <span class="token class-name">ViewModelProviders</span> <span class="token punctuation">.</span> <span class="token function">of</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token class-name">FeedViewModel</span> <span class="token punctuation">.</span> <span class="token keyword">class</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">/* * Step 2: Setup the adapter class for the RecyclerView * * */</span> binding <span class="token punctuation">.</span> listFeed <span class="token punctuation">.</span> <span class="token function">setLayoutManager</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">LinearLayoutManager</span> <span class="token punctuation">(</span> <span class="token function">getApplicationContext</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> adapter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FeedListAdapter</span> <span class="token punctuation">(</span> <span class="token function">getApplicationContext</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">/* * Step 4: When a new page is available, we call submitList() method * of the PagedListAdapter class * * */</span> feedViewModel <span class="token punctuation">.</span> <span class="token function">getArticleLiveData</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">observe</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> pagedList <span class="token operator">-></span> <span class="token punctuation">{</span> adapter <span class="token punctuation">.</span> <span class="token function">submitList</span> <span class="token punctuation">(</span> pagedList <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> feedViewModel <span class="token punctuation">.</span> <span class="token function">getNetworkState</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">observe</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">,</span> networkState <span class="token operator">-></span> <span class="token punctuation">{</span> adapter <span class="token punctuation">.</span> <span class="token function">setNetworkState</span> <span class="token punctuation">(</span> networkState <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> binding <span class="token punctuation">.</span> listFeed <span class="token punctuation">.</span> <span class="token function">setAdapter</span> <span class="token punctuation">(</span> adapter <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
With this article I hope everyone has a good experience and it will help everyone. Happy coding! Thanks for reading.
References:
https://proandroiddev.com/8-steps-to-implement-paging-library-in-android-d02500f7fffe https://github.com/anitaa1990/PagingLibrary-Sample