2
2
3
3
import android .support .annotation .NonNull ;
4
4
import android .support .annotation .Nullable ;
5
- import android .support .annotation .RestrictTo ;
6
5
import android .support .v7 .widget .RecyclerView ;
7
6
import android .util .Log ;
8
7
import android .view .ViewGroup ;
9
8
10
- import com .google .android .gms .tasks .OnCompleteListener ;
11
- import com .google .android .gms .tasks .Task ;
12
9
import com .google .firebase .firestore .DocumentSnapshot ;
13
10
import com .google .firebase .firestore .Query ;
14
- import com .google .firebase .firestore .QuerySnapshot ;
15
11
16
12
import java .util .ArrayList ;
17
13
import java .util .List ;
23
19
* See also {@link FirestoreInfiniteScrollListener}.
24
20
*/
25
21
public abstract class FirestorePagingAdapter <T , VH extends RecyclerView .ViewHolder >
26
- extends RecyclerView .Adapter <VH > {
22
+ extends RecyclerView .Adapter <VH >
23
+ implements Page .Listener {
27
24
28
25
private static final String TAG = "FirestorePagingAdapter" ;
29
26
@@ -42,7 +39,7 @@ public FirestorePagingAdapter(FirestorePagingOptions<T> options) {
42
39
mParser = options .getParser ();
43
40
mForwardQuery = options .getQuery ();
44
41
45
- Page page = new Page (0 );
42
+ Page page = new Page (0 , this );
46
43
mPages .add (page );
47
44
48
45
onLoadingStateChanged (true );
@@ -74,7 +71,7 @@ public void onBindViewHolder(VH holder, int position) {
74
71
public int getPagesLoaded () {
75
72
int count = 0 ;
76
73
for (Page page : mPages ) {
77
- if (page .getState () == PageState .LOADED ) {
74
+ if (page .getState () == Page . State .LOADED ) {
78
75
count ++;
79
76
}
80
77
}
@@ -89,13 +86,13 @@ public int getPagesLoaded() {
89
86
* specified in the options, unload the bottom-most page.
90
87
*/
91
88
public void loadPageUp () {
92
- if (countState ( PageState . LOADING ) > 0 ) {
89
+ if (hasAny ( Page . State . LOADING )) {
93
90
return ;
94
91
}
95
92
96
93
// Load the last UNLOADED page before the middle "core" of LOADED pages
97
- int firstLoaded = findFirstOfState (PageState .LOADED );
98
- int lastUnloadedBefore = findLastOfState (PageState .UNLOADED , firstLoaded );
94
+ int firstLoaded = findFirstOfState (Page . State .LOADED );
95
+ int lastUnloadedBefore = findLastOfState (Page . State .UNLOADED , firstLoaded );
99
96
100
97
if (lastUnloadedBefore != -1 ) {
101
98
logd ("RELOADING " + lastUnloadedBefore );
@@ -120,15 +117,15 @@ public void loadPageUp() {
120
117
* specified in the options, unload the top-most page.
121
118
*/
122
119
public void loadNextPage () {
123
- if (countState ( PageState . LOADING ) > 0 ) {
120
+ if (hasAny ( Page . State . LOADING )) {
124
121
return ;
125
122
}
126
123
127
124
// There are two cases here
128
125
// 1. Need to load a whole new page
129
126
// 2. Need to load an UNLOADED bottom page
130
127
131
- int lastLoaded = findLastOfState (PageState .LOADED );
128
+ int lastLoaded = findLastOfState (Page . State .LOADED );
132
129
133
130
if (lastLoaded == mPages .size () - 1 ) {
134
131
// Case 1: Load a new page at the bottom
@@ -143,7 +140,7 @@ public void loadNextPage() {
143
140
144
141
// Add and start loading
145
142
int nextPageIndex = mPages .size ();
146
- Page nextPage = new Page (nextPageIndex );
143
+ Page nextPage = new Page (nextPageIndex , this );
147
144
mPages .add (nextPage );
148
145
149
146
logd ("LOADING " + nextPageIndex );
@@ -152,7 +149,7 @@ public void loadNextPage() {
152
149
} else {
153
150
// Case 2: Need to load a previously unloaded page
154
151
// Find the first UNLOADED page after the middle "core" of loaded pages
155
- int firstUnloadedAfter = findFirstOfState (PageState .UNLOADED , lastLoaded );
152
+ int firstUnloadedAfter = findFirstOfState (Page . State .UNLOADED , lastLoaded );
156
153
157
154
logd ("RELOADING " + firstUnloadedAfter );
158
155
Page page = mPages .get (firstUnloadedAfter );
@@ -214,29 +211,50 @@ public T get(int index) {
214
211
return mParser .parseSnapshot (getSnapshot (index ));
215
212
}
216
213
214
+ @ Override
215
+ public void onPageStateChanged (Page page , Page .State state ) {
216
+ if (state == Page .State .LOADING ) {
217
+ onLoadingStateChanged (true );
218
+ } else {
219
+ onLoadingStateChanged (hasAny (Page .State .LOADING ));
220
+ }
221
+
222
+ if (state == Page .State .LOADED ) {
223
+ onPageLoaded (page .getIndex (), page .size ());
224
+ }
225
+
226
+ if (state == Page .State .UNLOADED ) {
227
+ onPageUnloaded (page .getIndex (), page .size ());
228
+ }
229
+ }
230
+
231
+ @ Override
232
+ public void onPageError (Page page , Exception ex ) {
233
+ Log .w (TAG , "Failed to get page" , ex );
234
+ // TODO: Remove page?
235
+ }
236
+
217
237
/**
218
238
* Called when a page begins or finishes loading, to indicate if there are any current loading
219
239
* operations going on.
220
240
*
221
241
* Useful to override and control UI elements such as a progress bar or loading spinner.
222
- * @param isLoading
223
242
*/
224
- // TODO: Better interface
225
243
protected void onLoadingStateChanged (boolean isLoading ) {
226
244
// No-op, this is for overriding.
227
245
}
228
246
229
247
private void unloadTopPage () {
230
248
// Find first loaded page
231
- int firstLoaded = findFirstOfState (PageState .LOADED );
249
+ int firstLoaded = findFirstOfState (Page . State .LOADED );
232
250
if (firstLoaded != -1 ) {
233
251
mPages .get (firstLoaded ).unload ();
234
252
logd ("UNLOADING " + firstLoaded );
235
253
}
236
254
}
237
255
238
256
private void unloadBottomPage () {
239
- int lastLoaded = findLastOfState (PageState .LOADED );
257
+ int lastLoaded = findLastOfState (Page . State .LOADED );
240
258
if (lastLoaded != -1 ) {
241
259
mPages .get (lastLoaded ).unload ();
242
260
logd ("UNLOADING " + lastLoaded );
@@ -251,7 +269,7 @@ private void onPageLoaded(int index, int size) {
251
269
252
270
notifyItemRangeInserted (itemsBefore , size );
253
271
254
- if (countState ( PageState . LOADING ) > 0 ) {
272
+ if (hasAny ( Page . State . LOADING )) {
255
273
onLoadingStateChanged (true );
256
274
} else {
257
275
onLoadingStateChanged (false );
@@ -267,11 +285,11 @@ private void onPageUnloaded(int index, int size) {
267
285
notifyItemRangeRemoved (itemsBefore , size );
268
286
}
269
287
270
- private int findFirstOfState (PageState state ) {
288
+ private int findFirstOfState (Page . State state ) {
271
289
return findFirstOfState (state , 0 );
272
290
}
273
291
274
- private int findFirstOfState (PageState state , int startingAt ) {
292
+ private int findFirstOfState (Page . State state , int startingAt ) {
275
293
for (int i = startingAt ; i < mPages .size (); i ++) {
276
294
Page page = mPages .get (i );
277
295
if (page .getState () == state ) {
@@ -282,11 +300,11 @@ private int findFirstOfState(PageState state, int startingAt) {
282
300
return -1 ;
283
301
}
284
302
285
- private int findLastOfState (PageState state ) {
303
+ private int findLastOfState (Page . State state ) {
286
304
return findLastOfState (state , mPages .size () - 1 );
287
305
}
288
306
289
- private int findLastOfState (PageState state , int endingAt ) {
307
+ private int findLastOfState (Page . State state , int endingAt ) {
290
308
for (int i = endingAt ; i >= 0 ; i --) {
291
309
Page page = mPages .get (i );
292
310
if (page .getState () == state ) {
@@ -297,15 +315,14 @@ private int findLastOfState(PageState state, int endingAt) {
297
315
return -1 ;
298
316
}
299
317
300
- private int countState (PageState state ) {
301
- int count = 0 ;
318
+ private boolean hasAny (Page .State state ) {
302
319
for (Page page : mPages ) {
303
320
if (page .getState () == state ) {
304
- count ++ ;
321
+ return true ;
305
322
}
306
323
}
307
324
308
- return count ;
325
+ return false ;
309
326
}
310
327
311
328
@ Nullable
@@ -350,97 +367,9 @@ private Query queryAfter(@Nullable DocumentSnapshot startAfter) {
350
367
return query ;
351
368
}
352
369
353
- private void logd (String message ) {
370
+ private static void logd (String message ) {
354
371
if (Log .isLoggable (TAG , Log .DEBUG )) {
355
372
Log .d (TAG , message );
356
373
}
357
374
}
358
-
359
- @ RestrictTo (RestrictTo .Scope .LIBRARY_GROUP )
360
- private enum PageState {
361
- LOADING ,
362
- LOADED ,
363
- UNLOADED
364
- }
365
-
366
- @ RestrictTo (RestrictTo .Scope .LIBRARY_GROUP )
367
- private class Page implements OnCompleteListener <QuerySnapshot > {
368
-
369
- private final int mIndex ;
370
- private PageState mState ;
371
- private DocumentSnapshot mFirstSnapshot ;
372
-
373
- private List <DocumentSnapshot > mSnapshots = new ArrayList <>();
374
-
375
- public Page (int index ) {
376
- mIndex = index ;
377
- mState = PageState .UNLOADED ;
378
- }
379
-
380
- public void load (Query query ) {
381
- if (mState == PageState .LOADING ) {
382
- return ;
383
- }
384
-
385
- mState = PageState .LOADING ;
386
- onLoadingStateChanged (true );
387
- query .get ().addOnCompleteListener (this );
388
- }
389
-
390
- public void unload () {
391
- int size = mSnapshots .size ();
392
- mSnapshots .clear ();
393
-
394
- onPageUnloaded (mIndex , size );
395
- mState = PageState .UNLOADED ;
396
- }
397
-
398
- @ Override
399
- public void onComplete (@ NonNull Task <QuerySnapshot > task ) {
400
- // TODO: Better error handling
401
- if (!task .isSuccessful ()) {
402
- Log .w (TAG , "Failed to get page" , task .getException ());
403
- }
404
-
405
- // Add all snapshots
406
- mSnapshots .addAll (task .getResult ().getDocuments ());
407
-
408
- // Set first in page
409
- if (mSnapshots .isEmpty ()) {
410
- mFirstSnapshot = null ;
411
- } else {
412
- mFirstSnapshot = mSnapshots .get (0 );
413
- }
414
-
415
- // Mark page as loaded
416
- logd ("LOADED " + mIndex );
417
- mState = PageState .LOADED ;
418
- onPageLoaded (mIndex , mSnapshots .size ());
419
- }
420
-
421
- public PageState getState () {
422
- return mState ;
423
- }
424
-
425
- public DocumentSnapshot get (int index ) {
426
- return mSnapshots .get (index );
427
- }
428
-
429
- public int size () {
430
- return mSnapshots .size ();
431
- }
432
-
433
- @ Nullable
434
- public DocumentSnapshot getFirst () {
435
- return mFirstSnapshot ;
436
- }
437
-
438
- @ Nullable
439
- public DocumentSnapshot getLast () {
440
- if (mSnapshots == null || mSnapshots .isEmpty ()) {
441
- return null ;
442
- }
443
- return mSnapshots .get (mSnapshots .size () - 1 );
444
- }
445
- }
446
375
}
0 commit comments