Skip to content

Commit d08eaa0

Browse files
SUPERCILEXsamtstern
authored andcommitted
Let devs intercept onChanged events and control when to update their adapter (firebase#488)
1 parent ca3362c commit d08eaa0

File tree

9 files changed

+166
-101
lines changed

9 files changed

+166
-101
lines changed

app/src/main/java/com/firebase/uidemo/database/ChatActivity.java

+31-18
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.firebase.uidemo.database;
1616

17+
import android.content.Context;
1718
import android.graphics.PorterDuff;
1819
import android.graphics.drawable.GradientDrawable;
1920
import android.graphics.drawable.RotateDrawable;
@@ -37,6 +38,7 @@
3738
import com.firebase.ui.database.FirebaseRecyclerAdapter;
3839
import com.firebase.uidemo.R;
3940
import com.google.android.gms.tasks.OnCompleteListener;
41+
import com.google.android.gms.tasks.OnSuccessListener;
4042
import com.google.android.gms.tasks.Task;
4143
import com.google.firebase.auth.AuthResult;
4244
import com.google.firebase.auth.FirebaseAuth;
@@ -86,9 +88,9 @@ public void onClick(View v) {
8688
Chat chat = new Chat(name, mMessageEdit.getText().toString(), uid);
8789
mChatRef.push().setValue(chat, new DatabaseReference.CompletionListener() {
8890
@Override
89-
public void onComplete(DatabaseError databaseError, DatabaseReference reference) {
90-
if (databaseError != null) {
91-
Log.e(TAG, "Failed to write message", databaseError.toException());
91+
public void onComplete(DatabaseError error, DatabaseReference reference) {
92+
if (error != null) {
93+
Log.e(TAG, "Failed to write message", error.toException());
9294
}
9395
}
9496
});
@@ -97,11 +99,10 @@ public void onComplete(DatabaseError databaseError, DatabaseReference reference)
9799
}
98100
});
99101

100-
mMessages = (RecyclerView) findViewById(R.id.messagesList);
101-
102102
mManager = new LinearLayoutManager(this);
103103
mManager.setReverseLayout(false);
104104

105+
mMessages = (RecyclerView) findViewById(R.id.messagesList);
105106
mMessages.setHasFixedSize(false);
106107
mMessages.setLayoutManager(mManager);
107108
}
@@ -145,7 +146,6 @@ private void attachRecyclerViewAdapter() {
145146
Query lastFifty = mChatRef.limitToLast(50);
146147
mRecyclerViewAdapter = new FirebaseRecyclerAdapter<Chat, ChatHolder>(
147148
Chat.class, R.layout.message, ChatHolder.class, lastFifty) {
148-
149149
@Override
150150
public void populateViewHolder(ChatHolder chatView, Chat chat, int position) {
151151
chatView.setName(chat.getName());
@@ -180,20 +180,13 @@ public void onItemRangeInserted(int positionStart, int itemCount) {
180180
private void signInAnonymously() {
181181
Toast.makeText(this, "Signing in...", Toast.LENGTH_SHORT).show();
182182
mAuth.signInAnonymously()
183-
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
183+
.addOnSuccessListener(this, new OnSuccessListener<AuthResult>() {
184184
@Override
185-
public void onComplete(@NonNull Task<AuthResult> task) {
186-
Log.d(TAG, "signInAnonymously:onComplete:" + task.isSuccessful());
187-
if (task.isSuccessful()) {
188-
Toast.makeText(ChatActivity.this, "Signed In",
189-
Toast.LENGTH_SHORT).show();
190-
attachRecyclerViewAdapter();
191-
} else {
192-
Toast.makeText(ChatActivity.this, "Sign In Failed",
193-
Toast.LENGTH_SHORT).show();
194-
}
185+
public void onSuccess(AuthResult result) {
186+
attachRecyclerViewAdapter();
195187
}
196-
});
188+
})
189+
.addOnCompleteListener(new SignInResultNotifier(this));
197190
}
198191

199192
public boolean isSignedIn() {
@@ -297,4 +290,24 @@ public void setText(String text) {
297290
mTextField.setText(text);
298291
}
299292
}
293+
294+
/**
295+
* Notifies the user of sign in successes or failures beyond the lifecycle of an activity.
296+
*/
297+
private static class SignInResultNotifier implements OnCompleteListener<AuthResult> {
298+
private Context mContext;
299+
300+
public SignInResultNotifier(Context context) {
301+
mContext = context.getApplicationContext();
302+
}
303+
304+
@Override
305+
public void onComplete(@NonNull Task<AuthResult> task) {
306+
if (task.isSuccessful()) {
307+
Toast.makeText(mContext, R.string.signed_in, Toast.LENGTH_SHORT).show();
308+
} else {
309+
Toast.makeText(mContext, R.string.sign_in_failed, Toast.LENGTH_SHORT).show();
310+
}
311+
}
312+
}
300313
}

app/src/main/res/values/strings.xml

+2
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,6 @@
6767

6868
<!-- strings for Auth UI demo activities -->
6969
<string name="start_chatting">No messages. Start chatting at the bottom!</string>
70+
<string name="sign_in_failed">Sign In Failed</string>
71+
<string name="signed_in">Signed In</string>
7072
</resources>

database/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ ref.limitToLast(5).addValueEventListener(new ValueEventListener() {
8686
}
8787
}
8888
@Override
89-
public void onCancelled(DatabaseError firebaseError) {
90-
Log.e("Chat", "The read failed: " + firebaseError.getText());
89+
public void onCancelled(DatabaseError error) {
90+
Log.e("Chat", "The read failed: " + error.getText());
9191
}
9292
});
9393
```

database/src/androidTest/java/com/firebase/ui/database/TestUtils.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,19 @@ public static void runAndWaitUntil(FirebaseArray array,
3737
Runnable task,
3838
Callable<Boolean> done) throws InterruptedException {
3939
final Semaphore semaphore = new Semaphore(0);
40-
array.setOnChangedListener(new FirebaseArray.OnChangedListener() {
4140

41+
array.setOnChangedListener(new ChangeEventListener() {
4242
@Override
43-
public void onChildChanged(EventType type, int index, int oldIndex) {
43+
public void onChildChanged(ChangeEventListener.EventType type, int index, int oldIndex) {
4444
semaphore.release();
4545
}
4646

4747
@Override
4848
public void onDataChanged() {}
4949

5050
@Override
51-
public void onCancelled(DatabaseError databaseError) {
52-
throw new IllegalStateException(databaseError.toException());
51+
public void onCancelled(DatabaseError error) {
52+
throw new IllegalStateException(error.toException());
5353
}
5454
});
5555
task.run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.firebase.ui.database;
2+
3+
import com.google.firebase.database.ChildEventListener;
4+
import com.google.firebase.database.DataSnapshot;
5+
import com.google.firebase.database.DatabaseError;
6+
7+
public interface ChangeEventListener {
8+
/**
9+
* The type of event received when a child has been updated.
10+
*/
11+
enum EventType {
12+
/**
13+
* An onChildAdded event was received.
14+
*
15+
* @see ChildEventListener#onChildAdded(DataSnapshot, String)
16+
*/
17+
ADDED,
18+
/**
19+
* An onChildChanged event was received.
20+
*
21+
* @see ChildEventListener#onChildChanged(DataSnapshot, String)
22+
*/
23+
CHANGED,
24+
/**
25+
* An onChildRemoved event was received.
26+
*
27+
* @see ChildEventListener#onChildRemoved(DataSnapshot)
28+
*/
29+
REMOVED,
30+
/**
31+
* An onChildMoved event was received.
32+
*
33+
* @see ChildEventListener#onChildMoved(DataSnapshot, String)
34+
*/
35+
MOVED
36+
}
37+
38+
/**
39+
* A callback for when a child has changed in FirebaseArray.
40+
*
41+
* @param type The type of event received
42+
* @param index The index at which the change occurred
43+
* @param oldIndex If {@code type} is a moved event, the previous index of the moved child.
44+
* For any other event, {@code oldIndex} will be -1.
45+
*/
46+
void onChildChanged(EventType type, int index, int oldIndex);
47+
48+
/** This method will be triggered each time updates from the database have been completely processed.
49+
* So the first time this method is called, the initial data has been loaded - including the case
50+
* when no data at all is available. Each next time the method is called, a complete update (potentially
51+
* consisting of updates to multiple child items) has been completed.
52+
* <p>
53+
* You would typically override this method to hide a loading indicator (after the initial load) or
54+
* to complete a batch update to a UI element.
55+
*/
56+
void onDataChanged();
57+
58+
/**
59+
* This method will be triggered in the event that this listener either failed at the server,
60+
* or is removed as a result of the security and Firebase Database rules.
61+
*
62+
* @param error A description of the error that occurred
63+
*/
64+
void onCancelled(DatabaseError error);
65+
}

database/src/main/java/com/firebase/ui/database/FirebaseArray.java

+10-21
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,8 @@
2727
* This class implements an array-like collection on top of a Firebase location.
2828
*/
2929
class FirebaseArray implements ChildEventListener, ValueEventListener {
30-
public interface OnChangedListener {
31-
enum EventType {ADDED, CHANGED, REMOVED, MOVED}
32-
33-
void onChildChanged(EventType type, int index, int oldIndex);
34-
35-
void onDataChanged();
36-
37-
void onCancelled(DatabaseError databaseError);
38-
39-
}
40-
4130
private Query mQuery;
42-
private OnChangedListener mListener;
31+
private ChangeEventListener mListener;
4332
private List<DataSnapshot> mSnapshots = new ArrayList<>();
4433

4534
public FirebaseArray(Query ref) {
@@ -80,21 +69,21 @@ public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
8069
index = getIndexForKey(previousChildKey) + 1;
8170
}
8271
mSnapshots.add(index, snapshot);
83-
notifyChangedListeners(OnChangedListener.EventType.ADDED, index);
72+
notifyChangedListeners(ChangeEventListener.EventType.ADDED, index);
8473
}
8574

8675
@Override
8776
public void onChildChanged(DataSnapshot snapshot, String previousChildKey) {
8877
int index = getIndexForKey(snapshot.getKey());
8978
mSnapshots.set(index, snapshot);
90-
notifyChangedListeners(OnChangedListener.EventType.CHANGED, index);
79+
notifyChangedListeners(ChangeEventListener.EventType.CHANGED, index);
9180
}
9281

9382
@Override
9483
public void onChildRemoved(DataSnapshot snapshot) {
9584
int index = getIndexForKey(snapshot.getKey());
9685
mSnapshots.remove(index);
97-
notifyChangedListeners(OnChangedListener.EventType.REMOVED, index);
86+
notifyChangedListeners(ChangeEventListener.EventType.REMOVED, index);
9887
}
9988

10089
@Override
@@ -103,7 +92,7 @@ public void onChildMoved(DataSnapshot snapshot, String previousChildKey) {
10392
mSnapshots.remove(oldIndex);
10493
int newIndex = previousChildKey == null ? 0 : (getIndexForKey(previousChildKey) + 1);
10594
mSnapshots.add(newIndex, snapshot);
106-
notifyChangedListeners(OnChangedListener.EventType.MOVED, newIndex, oldIndex);
95+
notifyChangedListeners(ChangeEventListener.EventType.MOVED, newIndex, oldIndex);
10796
}
10897

10998
@Override
@@ -116,23 +105,23 @@ public void onCancelled(DatabaseError error) {
116105
notifyCancelledListeners(error);
117106
}
118107

119-
public void setOnChangedListener(OnChangedListener listener) {
108+
public void setOnChangedListener(ChangeEventListener listener) {
120109
mListener = listener;
121110
}
122111

123-
protected void notifyChangedListeners(OnChangedListener.EventType type, int index) {
112+
protected void notifyChangedListeners(ChangeEventListener.EventType type, int index) {
124113
notifyChangedListeners(type, index, -1);
125114
}
126115

127-
protected void notifyChangedListeners(OnChangedListener.EventType type, int index, int oldIndex) {
116+
protected void notifyChangedListeners(ChangeEventListener.EventType type, int index, int oldIndex) {
128117
if (mListener != null) {
129118
mListener.onChildChanged(type, index, oldIndex);
130119
}
131120
}
132121

133-
protected void notifyCancelledListeners(DatabaseError databaseError) {
122+
protected void notifyCancelledListeners(DatabaseError error) {
134123
if (mListener != null) {
135-
mListener.onCancelled(databaseError);
124+
mListener.onCancelled(error);
136125
}
137126
}
138127
}

database/src/main/java/com/firebase/ui/database/FirebaseIndexArray.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class FirebaseIndexArray extends FirebaseArray {
3232
private static final String TAG = FirebaseIndexArray.class.getSimpleName();
3333

3434
private Query mQuery;
35-
private OnChangedListener mListener;
35+
private ChangeEventListener mListener;
3636
private Map<Query, ValueEventListener> mRefs = new HashMap<>();
3737
private List<DataSnapshot> mDataSnapshots = new ArrayList<>();
3838

@@ -107,7 +107,7 @@ public void onChildRemoved(DataSnapshot keySnapshot) {
107107

108108
if (isMatch(index, key)) {
109109
mDataSnapshots.remove(index);
110-
notifyChangedListeners(OnChangedListener.EventType.REMOVED, index);
110+
notifyChangedListeners(ChangeEventListener.EventType.REMOVED, index);
111111
}
112112
}
113113

@@ -124,7 +124,7 @@ public void onChildMoved(DataSnapshot keySnapshot, String previousChildKey) {
124124
DataSnapshot snapshot = mDataSnapshots.remove(oldIndex);
125125
int newIndex = getIndexForKey(key);
126126
mDataSnapshots.add(newIndex, snapshot);
127-
notifyChangedListeners(OnChangedListener.EventType.MOVED, newIndex, oldIndex);
127+
notifyChangedListeners(ChangeEventListener.EventType.MOVED, newIndex, oldIndex);
128128
}
129129
}
130130

@@ -135,7 +135,7 @@ public void onCancelled(DatabaseError error) {
135135
}
136136

137137
@Override
138-
public void setOnChangedListener(OnChangedListener listener) {
138+
public void setOnChangedListener(ChangeEventListener listener) {
139139
super.setOnChangedListener(listener);
140140
mListener = listener;
141141
}
@@ -149,15 +149,15 @@ public void onDataChange(DataSnapshot snapshot) {
149149
if (snapshot.getValue() != null) {
150150
if (!isMatch(index, key)) {
151151
mDataSnapshots.add(index, snapshot);
152-
notifyChangedListeners(OnChangedListener.EventType.ADDED, index);
152+
notifyChangedListeners(ChangeEventListener.EventType.ADDED, index);
153153
} else {
154154
mDataSnapshots.set(index, snapshot);
155-
notifyChangedListeners(OnChangedListener.EventType.CHANGED, index);
155+
notifyChangedListeners(ChangeEventListener.EventType.CHANGED, index);
156156
}
157157
} else {
158158
if (isMatch(index, key)) {
159159
mDataSnapshots.remove(index);
160-
notifyChangedListeners(OnChangedListener.EventType.REMOVED, index);
160+
notifyChangedListeners(ChangeEventListener.EventType.REMOVED, index);
161161
} else {
162162
Log.w(TAG, "Key not found at ref: " + snapshot.getRef());
163163
}

0 commit comments

Comments
 (0)