Skip to content

This change allows easy detection of the list being empty *and* respo… #487

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 10, 2017
Merged
13 changes: 12 additions & 1 deletion app/src/main/java/com/firebase/uidemo/database/ChatActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ public class ChatActivity extends AppCompatActivity implements FirebaseAuth.Auth
private static final String TAG = "RecyclerViewDemo";

private FirebaseAuth mAuth;
private DatabaseReference mRef;
private DatabaseReference mChatRef;
private Button mSendButton;
private EditText mMessageEdit;

private RecyclerView mMessages;
private LinearLayoutManager mManager;
private FirebaseRecyclerAdapter<Chat, ChatHolder> mRecyclerViewAdapter;
private View mEmptyListView;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand All @@ -70,7 +72,10 @@ protected void onCreate(Bundle savedInstanceState) {
mSendButton = (Button) findViewById(R.id.sendButton);
mMessageEdit = (EditText) findViewById(R.id.messageEdit);

mChatRef = FirebaseDatabase.getInstance().getReference().child("chats");
mEmptyListView = findViewById(R.id.emptyTextView);

mRef = FirebaseDatabase.getInstance().getReference();
mChatRef = mRef.child("chats");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@puf looks like the merge didn't work (mChatRef got split into a nonexistent mRef for some reason).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I split into two refs and apparently forgot to initialize one when resolving the conflict. It was my first time using the web conflict resolution editor and I must've borked something. I'll fix it tomorrow back at my desktop.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh cool! I haven't been able to try that out yet. Github just needs to add checks to make sure your code compiles 😄 (oh, and why not add Intellij while we're at it and just write all of your code for you! 😄)


mSendButton.setOnClickListener(new View.OnClickListener() {
@Override
Expand Down Expand Up @@ -153,6 +158,12 @@ public void populateViewHolder(ChatHolder chatView, Chat chat, int position) {
chatView.setIsSender(false);
}
}

@Override
protected void onDataChanged() {
// if there are no chat messages, show a view that invites the user to add a message
mEmptyListView.setVisibility(mRecyclerViewAdapter.getItemCount() == 0 ? View.VISIBLE : View.INVISIBLE);
}
};

// Scroll to bottom on new messages
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/layout/activity_chat.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
android:layout_height="match_parent"
tools:context=".database.ChatActivity">

<TextView
android:id="@+id/emptyTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/start_chatting"
android:padding="16dp" />

<android.support.v7.widget.RecyclerView
android:id="@+id/messagesList"
android:layout_width="match_parent"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,7 @@
<string name="choose_image">Choose Image</string>
<string name="accessibility_downloaded_image">Downloaded image</string>
<string name="drive_file">Drive File</string>

<!-- strings for Auth UI demo activities -->
<string name="start_chatting">No messages. Start chatting at the bottom!</string>
</resources>
19 changes: 15 additions & 4 deletions database/src/main/java/com/firebase/ui/database/FirebaseArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,24 @@
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;
import java.util.List;

/**
* This class implements an array-like collection on top of a Firebase location.
*/
class FirebaseArray implements ChildEventListener {
class FirebaseArray implements ChildEventListener, ValueEventListener {
public interface OnChangedListener {
enum EventType {ADDED, CHANGED, REMOVED, MOVED}

void onChanged(EventType type, int index, int oldIndex);
void onChildChanged(EventType type, int index, int oldIndex);

void onDataChanged();

void onCancelled(DatabaseError databaseError);

}

private Query mQuery;
Expand All @@ -41,10 +45,12 @@ enum EventType {ADDED, CHANGED, REMOVED, MOVED}
public FirebaseArray(Query ref) {
mQuery = ref;
mQuery.addChildEventListener(this);
mQuery.addValueEventListener(this);
}

public void cleanup() {
mQuery.removeEventListener(this);
mQuery.removeEventListener((ValueEventListener) this);
mQuery.removeEventListener((ChildEventListener) this);
}

public int getCount() {
Expand Down Expand Up @@ -100,6 +106,11 @@ public void onChildMoved(DataSnapshot snapshot, String previousChildKey) {
notifyChangedListeners(OnChangedListener.EventType.MOVED, newIndex, oldIndex);
}

@Override
public void onDataChange(DataSnapshot dataSnapshot) {
mListener.onDataChanged();
}

@Override
public void onCancelled(DatabaseError error) {
notifyCancelledListeners(error);
Expand All @@ -115,7 +126,7 @@ protected void notifyChangedListeners(OnChangedListener.EventType type, int inde

protected void notifyChangedListeners(OnChangedListener.EventType type, int index, int oldIndex) {
if (mListener != null) {
mListener.onChanged(type, index, oldIndex);
mListener.onChildChanged(type, index, oldIndex);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,34 @@ public abstract class FirebaseListAdapter<T> extends BaseAdapter {

mSnapshots.setOnChangedListener(new FirebaseArray.OnChangedListener() {
@Override
public void onChanged(EventType type, int index, int oldIndex) {
public void onChildChanged(EventType type, int index, int oldIndex) {
notifyDataSetChanged();
}

@Override
public void onCancelled(DatabaseError databaseError) {
FirebaseListAdapter.this.onCancelled(databaseError);
}

@Override
public void onDataChanged() {
FirebaseListAdapter.this.onDataChanged();
}
});
}


/* This method will be triggered each time updates from the database have been completely processed.
* So the first time this method is called, the initial data has been loaded - including the case
* when no data at all is available. Each next time the method is called, a complete update (potentially
* consisting of updates to multiple child items) has been completed.
* <p>
* You would typically override this method to hide a loading indicator (after the initial load) or
* to complete a batch update to a UI element.
*/
protected void onDataChanged() {
}

/**
* @param activity The activity containing the ListView
* @param modelClass Firebase will marshall the data at a location into
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public abstract class FirebaseRecyclerAdapter<T, VH extends RecyclerView.ViewHol

mSnapshots.setOnChangedListener(new FirebaseArray.OnChangedListener() {
@Override
public void onChanged(EventType type, int index, int oldIndex) {
public void onChildChanged(EventType type, int index, int oldIndex) {
switch (type) {
case ADDED:
notifyItemInserted(index);
Expand All @@ -114,9 +114,25 @@ public void onChanged(EventType type, int index, int oldIndex) {
public void onCancelled(DatabaseError databaseError) {
FirebaseRecyclerAdapter.this.onCancelled(databaseError);
}

@Override
public void onDataChanged() {
FirebaseRecyclerAdapter.this.onDataChanged();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't we want to unify these names and pick either onReady or onDataChanged? Other than that, LGTM!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wasn't sure. In the context of FirebaseArray the name onDataChanged() is too close to the existing onChanged() name. But I like the name as a whole.

We could consider renaming onChanged() to onChildChanged() (keep its signature aside from the name-change). Since the interface isn't part of the public API (yet), we could do that in a minor version.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should go for the second option (with onChildChanged letting us use onDataChanged). It would make the api more consistent with the native Firebase apis and fits well in the context of my other PR: https://github.com/firebase/FirebaseUI-Android/pull/488/files#diff-3620a1e9acaa17bea769cfbc3079f39aR18.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, might as well change the signature now while it's still private and get the name you actually want.

}
});
}

/* This method will be triggered each time updates from the database have been completely processed.
* So the first time this method is called, the initial data has been loaded - including the case
* when no data at all is available. Each next time the method is called, a complete update (potentially
* consisting of updates to multiple child items) has been completed.
* <p>
* You would typically override this method to hide a loading indicator (after the initial load) or
* to complete a batch update to a UI element.
*/
protected void onDataChanged() {
}

/**
* @param modelClass Firebase will marshall the data at a location into
* an instance of a class that you provide
Expand Down