0

I have 2 reference points. Services and servicetypes. Now as you can see servicetypes has a foreign key for each service. see below image: Here

Now I want to set value listener in both points and read data and display them in a RecyclerView. Each service has multiple service types.

I have done it like this

    database = FirebaseDatabase.getInstance();
    myRef = database.getReference(getString(R.string.services));
    Query userQuery=myRef.child(FireBaseUtils.getFirebaseId());
    userQuery.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            ArrayList<Map<String,String>> temp=new ArrayList<>();

     for(DataSnapshot d: dataSnapshot.getChildren())
     {

      final Service  s=d.getValue(Service.class);
       String id=d.getKey();
         Log.d("TEST", ": "+id);

         serviceTypesReference=database.getReference(getString(R.string.servicetypes)).child(id);
         serviceTypesReference.addListenerForSingleValueEvent(new ValueEventListener() {

             @Override
             public void onDataChange(DataSnapshot dataSnapshot) {
                //services.clear();
                 ArrayList<ServiceType> serviceTypes=new ArrayList<>();
                 Service tempService=new Service(s.getName());
                 for(DataSnapshot dd:dataSnapshot.getChildren())
                 {
                     ServiceType st= dd.getValue(ServiceType.class);
                     Log.d("TEST", "typename: "+st.getName());
                     serviceTypes.add(st);
                 }
                 tempService.setServiceTypeArrayList(serviceTypes);

                 services.add(tempService);
                 serviceAdapter=new ServiceAdapter(services);
                 servicesRecyclerView.setAdapter(serviceAdapter);
             }

             @Override
             public void onCancelled(DatabaseError databaseError) {

             }
         });

             }            }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }
});

Here a service object contains a name and an ArrayList containing all service types it includes. List of these service objects is passed to the adapter of the RecyclerView.

Now, this does the job but is very inefficient and maybe can cause bugs I don't see right now. Is there a better way to do this?

Thanks in advance.

dhiraj uchil
  • 113
  • 10
  • So basically you are trying to display all `servicetypes` of each `service` or only the `servicetypes` of a single service like `Tiffin`? – Alex Mamo Nov 30 '18 at 13:19
  • I am tring to display all services along with the number of servicetypes inside them – dhiraj uchil Dec 01 '18 at 01:39

1 Answers1

1

I am tring to display all services along with the number of servicetypes inside them

To solve this, you should query your database twice. Assuming that getString(R.string.services) returns service, getString(R.string.servicetypes) returns servicetypes and FireBaseUtils.getFirebaseId() holds that id kPBgLQo9WrbhJ01eReOOWbox1Uy1, please the following lines of code:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = rootRef.child("services").child("kPBgLQo9WrbhJ01eReOOWbox1Uy1");
ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for(DataSnapshot ds : dataSnapshot.getChildren()) {
            String key = ds.getKey();
            String name = ds.child("name").getValue(String.class);

            DatabaseReference keyRef = rootRef.child("servicetypes").child(key);
            ValueEventListener eventListener = new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    long count = dataSnapshot.getChildrenCount();
                    Log.d(TAG, name + "(" + count + ")");
                }

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                    Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
                }
            };
            keyRef.addListenerForSingleValueEvent(eventListener);
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
    }
};
ref.addListenerForSingleValueEvent(valueEventListener);

I have hardcoded the name of the nodes to see it more clearly. The result in your logcat will be:

Tiffin(3)
Milk(x)
//And so on
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Sorry I couldn't try it yet, I will check now and update you :) – dhiraj uchil Dec 02 '18 at 08:50
  • Ok, keep me posted. – Alex Mamo Dec 02 '18 at 08:50
  • Hey, thanks for answering, Actually logging gives correct output here. I need to add those outputs into an ArrayList and pass them to an adapter. The only place where I can do it is inside the eventListener right? after this line: Log.d(TAG, name + "(" + count + ")"); and thanks for reminding me about errors :D – dhiraj uchil Dec 02 '18 at 08:55
  • Good to hear that it gives the correct output :) Yes, you should do that inside the callback. Please take a look **[here](https://stackoverflow.com/a/48623379/5246885)**. – Alex Mamo Dec 02 '18 at 09:04
  • The solution is fine but how is the data going into recycler view you have not shown that – DragonFire Mar 22 '19 at 06:00
  • @DragonFire I have showed but in another answer. Check **[this](https://stackoverflow.com/a/49384849/5246885)** out. – Alex Mamo Mar 22 '19 at 08:39