Reputation: 2547
Here is my sample Firebase Realtime DB
{
"devices": {
"123456": {
"device_mac_id": "123456",
"device_name": "BOX 12",
"id": "2"
},
"222222": {
"device_mac_id": "222222",
"device_name": "BOX 22",
"id": "3"
},
"888888": {
"device_mac_id": "888888",
"device_name": "BOX 88",
"id": "6"
}
},
"users": {
"UcI1REoXAoSC7mg4u7RGbw8gR2g2": {
"email_id": "[email protected]",
"full_name": "Ab Cd",
"id": "UcI1REoXAoSC7mg4u7RGbw8gR2g2",
"user_devices": {
"-MIbRGtT25ki36foJ6b5": "888888",
"-MIc-ORsWRqO45OJrBXg": "123456"
}
}
}
}
DashboardFragment.java
{
showProgressBar();
deviceModelArrayList.clear();
devicesAdapter.notifyDataSetChanged();
mDatabaseRef
.child("users")
.child(FirebaseAuth.getInstance().getUid())
.child("user_devices")
.orderByKey()
.addChildEventListener(
new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
Log.e(TAG,
"onChildAdded:"
+ " snapshot:" + snapshot.getValue()
+ " previousChildName:" + previousChildName);
getDeviceData(snapshot.getValue(String.class));
}
@Override
public void onChildChanged(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
Log.e(TAG,
"onChildChanged:"
+ " snapshot:" + snapshot.getValue()
+ " previousChildName:" + previousChildName);
}
@Override
public void onChildRemoved(@NonNull DataSnapshot snapshot) {
Log.e(TAG,
"onChildRemoved:"
+ " snapshot:" + snapshot.getValue());
}
@Override
public void onChildMoved(@NonNull DataSnapshot snapshot, @Nullable String previousChildName) {
Log.e(TAG,
"onChildMoved:"
+ " snapshot:" + snapshot.getValue()
+ " previousChildName:" + previousChildName);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Log.e(TAG,
"onCancelled:"
+ " error:" + error.toString());
}
});
}
private void getDeviceData(String deviceID) {
if (deviceID != null) {
mDatabaseRef
.child("devices")
.child(deviceID)
.addListenerForSingleValueEvent(
new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
hideProgressBar();
// This method is called once with the initial value and again
// whenever data at this location is updated.
UserModel.DeviceModel deviceModel = dataSnapshot.getValue(UserModel.DeviceModel.class);
Log.e(TAG, "onDataChange: devices: " + deviceModel.getDevice_name());
deviceModelArrayList.add(deviceModel);
devicesAdapter.notifyDataSetChanged();
}
@Override
public void onCancelled(DatabaseError error) {
hideProgressBar();
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
}
);
}
}
I want to show in RecyclerView but data keep on multiplying as onDataChanged, I'm adding object to ArrayList. Please suggest me if I'm wrong or best practices.
Upvotes: 0
Views: 58
Reputation: 2547
Thank you @Alex for your timely answer.
Meanwhile waiting for answers, I did some research on FirebaseUI for Realtime Database
dependencies {
// FirebaseUI for Firebase Realtime Database
implementation 'com.firebaseui:firebase-ui-database:x.y.z'
}
I felt more comfortable with FirebaseRecyclerAdapter as my challenge was dealing with handling Lists.
Here is my code snippets that worked for me.
firebaseRecyclerOptions =
new FirebaseRecyclerOptions
.Builder<String>()
.setQuery(mDatabaseRef.child("users").child(mFirebaseAuth.getUid()).child("user_devices"), String.class)
.build();
firebaseRecyclerAdapter =
new FirebaseRecyclerAdapter<String, DevicesViewHolder>(firebaseRecyclerOptions) {
@Override
protected void onBindViewHolder(@NonNull DevicesViewHolder holder, int position, @NonNull String deviceID) {
if (deviceID != null) {
mDatabaseRef
.child("devices")
.child(deviceID)
.addListenerForSingleValueEvent(
new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
hideProgressBar();
// This method is called once with the initial value and again
UserModel.DeviceModel deviceModel = dataSnapshot.getValue(UserModel.DeviceModel.class);
Log.e(TAG, "onDataChange: devices: " + deviceModel.getDevice_name());
holder.b.btnPowerBox.setText(deviceModel.getDevice_name());
}
@Override
public void onCancelled(DatabaseError error) {
hideProgressBar();
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
}
);
}
holder.b.btnPowerBox.setOnClickListener(view -> {
Log.d(TAG, "onBindViewHolder: Button clicked at position " + position);
});
}
@NonNull
@Override
public DevicesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemDevicesBinding bItem = ItemDevicesBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new DevicesViewHolder(bItem);
}
@Override
public void onDataChanged() {
// If there are no chat messages, show a view that invites the user to add an item to list.
b.tvEmptyListMessage.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
};
firebaseRecyclerAdapter.startListening();
b.rvDevices.setAdapter(firebaseRecyclerAdapter);
Upvotes: 0
Reputation: 139039
According to your last comment:
Yes, there are 3 devices but I have assigned only 2 to the user.
To get the DeviceModel
objects that correspond only to a specific user, you need to loop through the DataSnapshot object using the getChildren()
method twice, as shown in the following lines of code:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userDevicesRef = rootRef.child("users").child(uid).child("user_devices");
ValueEventListener valueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot userDeviceSnapshot : dataSnapshot.getChildren()) {
String deviceId = userDeviceSnapshot.getValue(String.class);
DatabaseReference userDevicesRef = rootRef.child("devices").child(deviceId);
ValueEventListener eventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot deviceSnapshot) {
UserModel.DeviceModel deviceModel = dataSnapshot.getValue(UserModel.DeviceModel.class);
Log.d("TAG", deviceModel.getDevice_name());
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
}
};
userDevicesRef.addListenerForSingleValueEvent(eventListener);
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
}
};
userDevicesRef.addListenerForSingleValueEvent(valueEventListener);
The result in the logcat will be:
BOX 88
BOX 12
But this is only to see that is working. In your case, you should add those objects to a the list and notify the adapter about changes.
Upvotes: 1