Skip to content

Commit c090b91

Browse files
committed
Added 'retry()' and 'refresh()' methods PR firebase#1603 issue firebase#1601
Added functionalities : 1. retry() : Retry the loading of data in RecyclerView after failure. 2. refresh() : Reload data in RecyclerView by clearing recent loaded data.
1 parent ba4fdae commit c090b91

File tree

4 files changed

+110
-23
lines changed

4 files changed

+110
-23
lines changed

app/src/main/java/com/firebase/uidemo/database/realtime/FirebaseDbPagingActivity.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
import android.os.Bundle;
55
import android.support.annotation.NonNull;
66
import android.support.annotation.Nullable;
7+
import android.support.v4.widget.SwipeRefreshLayout;
78
import android.support.v7.app.AppCompatActivity;
89
import android.support.v7.widget.LinearLayoutManager;
910
import android.support.v7.widget.RecyclerView;
1011
import android.util.Log;
1112
import android.view.LayoutInflater;
1213
import android.view.View;
1314
import android.view.ViewGroup;
14-
import android.widget.ProgressBar;
1515
import android.widget.TextView;
1616
import android.widget.Toast;
1717

@@ -33,8 +33,8 @@ public class FirebaseDbPagingActivity extends AppCompatActivity {
3333
@BindView(R.id.paging_recycler)
3434
RecyclerView mRecycler;
3535

36-
@BindView(R.id.paging_loading)
37-
ProgressBar mProgressBar;
36+
@BindView(R.id.swipe_refresh_layout)
37+
SwipeRefreshLayout mSwipeRefreshLayout;
3838

3939
private Query mQuery;
4040

@@ -65,7 +65,7 @@ private void setUpAdapter() {
6565
.build();
6666

6767
//Initializing Adapter
68-
FirebaseRecyclerPagingAdapter<Post, PostViewHolder> mAdapter =
68+
final FirebaseRecyclerPagingAdapter<Post, PostViewHolder> mAdapter =
6969
new FirebaseRecyclerPagingAdapter<Post, PostViewHolder>(options) {
7070
@NonNull
7171
@Override
@@ -88,33 +88,42 @@ protected void onLoadingStateChanged(@NonNull LoadingState state) {
8888
switch (state) {
8989
case LOADING_INITIAL:
9090
case LOADING_MORE:
91-
mProgressBar.setVisibility(View.VISIBLE);
91+
mSwipeRefreshLayout.setRefreshing(true);
9292
break;
9393

9494
case LOADED:
95-
mProgressBar.setVisibility(View.GONE);
95+
mSwipeRefreshLayout.setRefreshing(false);
9696
break;
9797

9898
case FINISHED:
99-
mProgressBar.setVisibility(View.GONE);
99+
mSwipeRefreshLayout.setRefreshing(false);
100100
Toast.makeText(getApplicationContext(), getString(R.string.paging_finished_message), Toast.LENGTH_SHORT).show();
101101
break;
102102

103103
case ERROR:
104-
mProgressBar.setVisibility(View.GONE);
104+
retry();
105105
break;
106106
}
107107
}
108108

109109
@Override
110110
protected void onError(DatabaseError databaseError) {
111-
mProgressBar.setVisibility(View.GONE);
111+
mSwipeRefreshLayout.setRefreshing(false);
112112
Log.e(TAG, databaseError.getMessage());
113113
}
114114
};
115115

116116
mRecycler.setLayoutManager(new LinearLayoutManager(this));
117117
mRecycler.setAdapter(mAdapter);
118+
119+
// Reload data on swipe
120+
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
121+
@Override
122+
public void onRefresh() {
123+
//Reload Data
124+
mAdapter.refresh();
125+
}
126+
});
118127
}
119128

120129
public static class Post {
Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,12 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<RelativeLayout
2+
<android.support.v4.widget.SwipeRefreshLayout
33
xmlns:android="http://schemas.android.com/apk/res/android"
44
xmlns:tools="http://schemas.android.com/tools"
5+
android:id="@+id/swipe_refresh_layout"
56
android:layout_width="match_parent"
67
android:layout_height="match_parent"
78
tools:context="com.firebase.uidemo.database.realtime.FirebaseDbPagingActivity">
89

9-
<ProgressBar
10-
android:id="@+id/paging_loading"
11-
style="?android:attr/progressBarStyleHorizontal"
12-
android:layout_width="match_parent"
13-
android:layout_height="wrap_content"
14-
android:layout_marginTop="-6dp"
15-
android:background="@android:color/transparent"
16-
android:indeterminate="true"
17-
tools:ignore="NegativeMargin" />
18-
1910
<android.support.v7.widget.RecyclerView
2011
android:id="@+id/paging_recycler"
2112
android:layout_width="match_parent"
@@ -27,4 +18,4 @@
2718
android:paddingRight="16dp"
2819
tools:listitem="@layout/item_post" />
2920

30-
</RelativeLayout>
21+
</android.support.v4.widget.SwipeRefreshLayout>

database/src/main/java/com/firebase/ui/database/paging/FirebaseDataSource.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import android.support.annotation.NonNull;
88
import android.support.annotation.Nullable;
99
import android.support.annotation.RestrictTo;
10+
import android.util.Log;
1011

1112
import com.google.firebase.database.DataSnapshot;
1213
import com.google.firebase.database.DatabaseError;
@@ -26,7 +27,6 @@
2627
*/
2728
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
2829
public class FirebaseDataSource extends PageKeyedDataSource<String, DataSnapshot> {
29-
3030
private static final String TAG = "FirebaseDataSource";
3131

3232
private Query mQuery;
@@ -38,6 +38,8 @@ public class FirebaseDataSource extends PageKeyedDataSource<String, DataSnapshot
3838
private static final String MESSAGE_DATABASE_NOT_FOUND = "Database not found at given child path !";
3939
private static final String DETAILS_DATABASE_NOT_FOUND = "Database Children Not Found in the specified child path. Please specify correct child path/reference";
4040

41+
private Runnable mRetryRunnable;
42+
4143
public static class Factory extends DataSource.Factory<String, DataSnapshot> {
4244

4345
private final Query mQuery;
@@ -60,6 +62,7 @@ public DataSource<String, DataSnapshot> create() {
6062
@Override
6163
public void loadInitial(@NonNull final LoadInitialParams<String> params,
6264
@NonNull final LoadInitialCallback<String, DataSnapshot> callback) {
65+
6366
// Set initial loading state
6467
mLoadingState.postValue(LoadingState.LOADING_INITIAL);
6568

@@ -81,16 +84,19 @@ public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
8184

8285
//Update State
8386
mLoadingState.postValue(LoadingState.LOADED);
87+
mRetryRunnable = null;
8488

8589
callback.onResult(data, lastKey, lastKey);
8690

8791
} else {
92+
mRetryRunnable = getRetryLoadInitial(params, callback);
8893
setDatabaseNotFoundError();
8994
}
9095
}
9196

9297
@Override
9398
public void onCancelled(@NonNull DatabaseError databaseError) {
99+
mRetryRunnable = getRetryLoadInitial(params, callback);
94100
setError(databaseError);
95101
}
96102
});
@@ -114,6 +120,7 @@ public void loadAfter(@NonNull final LoadParams<String> params,
114120
@Override
115121
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
116122
if (dataSnapshot.exists()) {
123+
117124
//Make List of DataSnapshot
118125
List<DataSnapshot> data = new ArrayList<>();
119126
String lastKey = null;
@@ -131,6 +138,7 @@ public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
131138

132139
//Update State
133140
mLoadingState.postValue(LoadingState.LOADED);
141+
mRetryRunnable = null;
134142

135143
//Detect End of Data
136144
if (data.isEmpty())
@@ -143,18 +151,58 @@ public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
143151
callback.onResult(data, lastKey);
144152

145153
} else {
146-
setDatabaseNotFoundError();
154+
mRetryRunnable = getRetryLoadAfter(params, callback);
155+
setDatabaseNotFoundError();
147156
}
148157

149158
}
150159

151160
@Override
152161
public void onCancelled(@NonNull DatabaseError databaseError) {
162+
mRetryRunnable = getRetryLoadAfter(params, callback);
153163
setError(databaseError);
154164
}
155165
});
156166
}
157167

168+
@NonNull
169+
private Runnable getRetryLoadAfter(@NonNull final LoadParams<String> params,
170+
@NonNull final LoadCallback<String, DataSnapshot> callback) {
171+
return new Runnable() {
172+
@Override
173+
public void run() {
174+
loadAfter(params, callback);
175+
}
176+
};
177+
}
178+
179+
@NonNull
180+
private Runnable getRetryLoadInitial(@NonNull final LoadInitialParams<String> params,
181+
@NonNull final LoadInitialCallback<String, DataSnapshot> callback) {
182+
return new Runnable() {
183+
@Override
184+
public void run() {
185+
loadInitial(params, callback);
186+
}
187+
};
188+
}
189+
190+
public void retry() {
191+
LoadingState currentState = mLoadingState.getValue();
192+
if (currentState != LoadingState.ERROR) {
193+
Log.w(TAG, "retry() not valid when in state: " + currentState);
194+
return;
195+
}
196+
197+
if (mRetryRunnable == null) {
198+
Log.w(TAG, "retry() called with no eligible retry runnable.");
199+
return;
200+
}
201+
202+
mRetryRunnable.run();
203+
}
204+
205+
158206
@Nullable
159207
private String getLastPageKey(@NonNull List<DataSnapshot> data) {
160208
if (data.isEmpty()) {

database/src/main/java/com/firebase/ui/database/paging/FirebaseRecyclerPagingAdapter.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import android.support.annotation.NonNull;
1313
import android.support.annotation.Nullable;
1414
import android.support.v7.widget.RecyclerView;
15+
import android.util.Log;
1516

1617
import com.firebase.ui.database.SnapshotParser;
1718
import com.google.firebase.database.DataSnapshot;
@@ -33,6 +34,15 @@ public abstract class FirebaseRecyclerPagingAdapter<T, VH extends RecyclerView.V
3334
private final LiveData<DatabaseError> mDatabaseError;
3435
private final LiveData<FirebaseDataSource> mDataSource;
3536

37+
38+
//Data Source Observer
39+
private final Observer<FirebaseDataSource> mDataSourceObserver = new Observer<FirebaseDataSource>() {
40+
@Override
41+
public void onChanged(@Nullable FirebaseDataSource source) {
42+
43+
}
44+
};
45+
3646
//State Observer
3747
private final Observer<LoadingState> mStateObserver = new Observer<LoadingState>() {
3848
@Override
@@ -109,6 +119,32 @@ public LiveData<DatabaseError> apply(PagedList<DataSnapshot> input) {
109119

110120
}
111121

122+
/**
123+
* If {@link #onLoadingStateChanged(LoadingState)} indicates error state, call this method
124+
* to attempt to retry the most recent failure.
125+
*/
126+
public void retry(){
127+
FirebaseDataSource mFirebaseDataSource = mDataSource.getValue();
128+
if (mFirebaseDataSource == null) {
129+
Log.w(TAG, "Called retry() when FirebaseDataSource is null!");
130+
return;
131+
}
132+
133+
mFirebaseDataSource.retry();
134+
}
135+
136+
/**
137+
* To attempt to refresh the list. It will reload the list from beginning.
138+
*/
139+
public void refresh(){
140+
FirebaseDataSource mFirebaseDataSource = mDataSource.getValue();
141+
if (mFirebaseDataSource == null) {
142+
Log.w(TAG, "Called refresh() when FirebaseDataSource is null!");
143+
return;
144+
}
145+
mFirebaseDataSource.invalidate();
146+
}
147+
112148
/**
113149
* Start listening to paging / scrolling events and populating adapter data.
114150
*/
@@ -117,6 +153,7 @@ public void startListening() {
117153
mPagedList.observeForever(mDataObserver);
118154
mLoadingState.observeForever(mStateObserver);
119155
mDatabaseError.observeForever(mErrorObserver);
156+
mDataSource.observeForever(mDataSourceObserver);
120157
}
121158

122159
/**
@@ -128,6 +165,7 @@ public void stopListening() {
128165
mPagedList.removeObserver(mDataObserver);
129166
mLoadingState.removeObserver(mStateObserver);
130167
mDatabaseError.removeObserver(mErrorObserver);
168+
mDataSource.removeObserver(mDataSourceObserver);
131169
}
132170

133171
@Override
@@ -162,4 +200,5 @@ protected void onError(@NonNull DatabaseError databaseError){
162200
public DatabaseReference getRef(int position){
163201
return getItem(position).getRef();
164202
}
203+
165204
}

0 commit comments

Comments
 (0)