I have users object as below:
{
\"deviceTokens\" : {
\"SgJd7o1hK7YbJnygnYWvaz4qkr42\" : {
\"c-sfcTB3iEA:APA91bEvuzhX1nlrhoxVmR69lvwu0H1zyRjOXd5b1
Actually, I didn't wanted to create my own adapter, because I believed that FirebaseUI would not have such a limitation, but I was wrong. Anyways, this is how I approached:
First of all fetch all the data from the User Object from FirebaseDatabase and then, filter on our end and finally, set that data:
FirebaseDatabase.getInstance().getReference().child("users")
.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterable<DataSnapshot> list = dataSnapshot.getChildren();
// Getting current user Id
String uid = getCurrentUserId();
// Filter User
List<User> userList = new ArrayList<>();
for (DataSnapshot dataSnapshot1 : list) {
if (!dataSnapshot1.getKey().equals(uid)) {
userList.add(dataSnapshot1.getValue(User.class));
}
}
// Setting data
mBaseRecyclerAdapter.setItems(userList);
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
I have created my own generic recycler adapter here: https://gist.github.com/chintansoni202/3c61aea787ae4bd49f26adee9dd40a08
One way to solve this and still use FirebaseRecyclerAdapter from FirebaseUI is to extend FirebaseArray like this:
import com.firebase.ui.database.FirebaseArray;
import com.firebase.ui.database.SnapshotParser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.Query;
import java.util.HashSet;
import java.util.Set;
public class FilterableFirebaseArray extends FirebaseArray {
private Set<String> excludes = new HashSet<>();
public FilterableFirebaseArray(Query query, Class aClass) {
super(query, aClass);
}
public FilterableFirebaseArray(Query query, SnapshotParser parser) {
super(query, parser);
}
public void addExclude(String key) {
excludes.add(key);
}
public void removeExclude(String key) {
excludes.remove(key);
}
@Override
public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
if (!excludes.contains(snapshot.getKey())) {
super.onChildAdded(snapshot, excludes.contains(previousChildKey)? null : previousChildKey);
}
}
@Override
public void onChildChanged(DataSnapshot snapshot, String previousChildKey) {
if (!excludes.contains(snapshot.getKey())) {
super.onChildChanged(snapshot, excludes.contains(previousChildKey)? null : previousChildKey);
}
}
@Override
public void onChildMoved(DataSnapshot snapshot, String previousChildKey) {
if (!excludes.contains(snapshot.getKey())) {
super.onChildMoved(snapshot, excludes.contains(previousChildKey)? null : previousChildKey);
}
}
@Override
public void onChildRemoved(DataSnapshot snapshot) {
if (!excludes.contains(snapshot.getKey())) {
super.onChildRemoved(snapshot);
}
}
}
…and then use it like this:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView userListView = (RecyclerView) findViewById(R.id.userList);
userListView.setLayoutManager(new LinearLayoutManager(this));
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Query query = ref.orderByValue();
ClassSnapshotParser parser = new ClassSnapshotParser<UserProfile>(UserProfile.class);
FilterableFirebaseArray filterableFirebaseArray = new FilterableFirebaseArray(query, parser);
filterableFirebaseArray.addExclude(FirebaseAuth.getInstance().getCurrentUser().getUid());
FirebaseRecyclerAdapter mAdapter = new FirebaseRecyclerAdapter<UserProfile, UserListEntryHolder>(
filterableFirebaseArray,
R.layout.userlist_entry,
UserListEntryHolder.class) {
@Override
protected void populateViewHolder(UserListEntryHolder viewHolder, UserProfile model, int position) {
viewHolder.bind(model);
}
};
userListView.setAdapter(mAdapter);
}
The "magic" happens in the overridden onChildAdded method where we ignore children identified by the specified keys. In this example I simply add the UID of the current user to the exclusion list. As this matches my database design.
You could easily extend the functionality to ignore children with specific properties.
Bonus: If you prefer the Kotlin way (like me) this is how you'd do it:
import com.firebase.ui.database.FirebaseArray
import com.firebase.ui.database.SnapshotParser
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.Query
class FilterableFirebaseArray<T> : FirebaseArray<T> {
val excludedKeys = HashSet<String?>()
constructor(query: Query, tClass: Class<T>) : super(query, tClass)
constructor(query: Query, parser: SnapshotParser<T>) : super(query, parser)
override fun onChildAdded(snapshot: DataSnapshot, previousChildKey: String?) {
if (!excludedKeys.contains(snapshot.key))
super.onChildAdded(snapshot, if (excludedKeys.contains(previousChildKey)) null else previousChildKey)
}
override fun onChildChanged(snapshot: DataSnapshot, previousChildKey: String?) {
if (!excludedKeys.contains(snapshot.key))
super.onChildChanged(snapshot, previousChildKey)
}
override fun onChildMoved(snapshot: DataSnapshot, previousChildKey: String?) {
if (!excludedKeys.contains(snapshot.key))
super.onChildMoved(snapshot, previousChildKey)
}
override fun onChildRemoved(snapshot: DataSnapshot) {
if (!excludedKeys.contains(snapshot.key))
super.onChildRemoved(snapshot)
}
}
…and then use it like this:
override fun onStart() {
super.onStart()
if (currentUser != null) {
userList.adapter = getAdapter()
}
}
private fun getAdapter(): FirebaseRecyclerAdapter<UserProfile, UserListEntryHolder> {
val query = userProfilesReference.orderByValue()
val parser = ClassSnapshotParser<UserProfile>(UserProfile::class.java)
val filterableFirebaseArray = FilterableFirebaseArray<UserProfile>(query, parser)
filterableFirebaseArray.excludes.add(currentUser?.uid)
return object : FirebaseRecyclerAdapter<UserProfile, UserListEntryHolder>(
filterableFirebaseArray,
R.layout.userlist_entry,
UserListEntryHolder::class.java) {
public override fun populateViewHolder(entryHolder: UserListEntryHolder, userProfile: UserProfile, position: Int) {
entryHolder.bind(userProfile)
}
}
}
Updated code to resolve IllegalArgumentExceptions related to onChildChanged, onChildMoved etc.