1

I am not sure if I am understanding some of the literature correctly. Android documentation says don't create unecessary objects. This article (Are Firebase queries scalable) mentions scalability with DB queries is ok, but I've also read its better to store your Query into an ArrayList and search through that instead of querying a large DB.

In my case I am using Firebase Realtime Database for Android and I'm wondering if I get a Child Node that has maybe 200 examples/child nodes, should I put each of these snapshots into a Model Class and then Add each of those to an ArrayList which can then be displayed in a RecyclerView? Or Should I run .getValue() on the fields and store them in another way?

I am specifically looking to see which Company ID's an Employer is associated to, and then go to the Companies node and Get the Business Names and Business Cities for that Employer

DB:

FirebaseDB

Here is my section of code in the activity:

companiesRef.addValueEventListener(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                for (DataSnapshot ds: dataSnapshot.getChildren()) {

                                    Log.i("companiesSnap", ds.toString());
                                    Log.i("KEYs", ds.getKey());
                                    companyIDKey = ds.getKey();
                                    //For each company ID in the Arraylist
                                    for (int i = 0; i < myCompanyIDsList.size(); i++) {
                                        //IF the IDs in arraylist from employee matches CompanyID from Companies node
                                        if(myCompanyIDsList.get(i).equals(companyIDKey)) {
                                            //IF THE ID matches, then get the associated company info
                                            Log.i("city", ds.child("businessCity").getValue().toString());
                                            Log.i("name", ds.child("businessName").getValue().toString());
                                            Businesses business = new Businesses(ds);
                                            myBusinessListItems.add(business);
                                            mAdapter.updateDataSet(myBusinessListItems);
                                        }
                                    }

Entire Class:

public class BusinessesActivity extends Activity {

    private Context mContext;
    LinearLayout mLinearLayout;
    private RecyclerView mRecyclerView;
    private MyAdapterBusiness mAdapter = new MyAdapterBusiness(this);
    private RecyclerView.LayoutManager mLayoutManager;
    ArrayList<Businesses> myBusinessListItems;
    ArrayList<String> myCompanyIDsList;
    DatabaseReference employeesRefID, companiesRef;
    FirebaseDatabase database;

    String currentUser, companyIDKey;

    TextView getData;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_businesses);


        //RECYCLERVIEW STUFF
        mRecyclerView = (RecyclerView) findViewById(R.id.b_recycler_view);

        mContext = getApplicationContext(); // Get the application context

        // Define a layout for RecyclerView
        mLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false);        //mLayoutManager = new LinearLayoutManager(mContext);
        mRecyclerView.setLayoutManager(mLayoutManager);

        // Initialize a new instance of RecyclerView Adapter instance
        mRecyclerView.setAdapter(mAdapter);

        //ARRAY List to Store EACH Company ID
        myCompanyIDsList = new ArrayList<String>();

        myBusinessListItems = new ArrayList<Businesses>();
        currentUser =
                FirebaseAuth.getInstance().getCurrentUser().getUid();

        database = FirebaseDatabase.getInstance();

        getData = (TextView) findViewById(R.id.getData);

        companiesRef = database.getReference("Companies").child("CompanyIDs");


        final DataSnapshotCallback callback = new DataSnapshotCallback() {
            @Override
            public void gotDataSnapshot(DataSnapshot snapshot) {
                EmployeeUser employee = new EmployeeUser(snapshot);


                //myCompanyIDsList.add(employee);

                try {
                    for (DataSnapshot ds : snapshot.getChildren()) {
                        //WITHIN each UserId check the PushID
                        Log.i("TAG", "checkIfIDExists: datasnapshot: " + ds);

                        myCompanyIDsList.add(ds.getValue(EmployeeUser.class).getID());
                        Log.i("arrayList", myCompanyIDsList.toString());

                        //}
                    }

                    //GO THROUGH EACH COMPANY ID AND FIND INFORMATION
                        companiesRef.addValueEventListener(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                for (DataSnapshot ds: dataSnapshot.getChildren()) {

                                    Log.i("companiesSnap", ds.toString());
                                    Log.i("KEYs", ds.getKey());
                                    companyIDKey = ds.getKey();
                                    //For each company ID in the Arraylist
                                    for (int i = 0; i < myCompanyIDsList.size(); i++) {
                                        //IF the IDs in arraylist from employee matches CompanyID from Companies node
                                        if(myCompanyIDsList.get(i).equals(companyIDKey)) {
                                            //IF THE ID matches, then get the associated company info
                                            Log.i("city", ds.child("businessCity").getValue().toString());
                                            Log.i("name", ds.child("businessName").getValue().toString());
                                            Businesses business = new Businesses(ds);
                                            myBusinessListItems.add(business);
                                            mAdapter.updateDataSet(myBusinessListItems);
                                        }
                                    }


                                    }

                                }
                            @Override
                            public void onCancelled(DatabaseError databaseError) {
                                Log.d("Cancelled", databaseError.toString());
                            }

                        }); //END COMPANIES EVENT LISTENER

                    //} //END FOR
                }  //END TRY

                catch (Exception e) {
                    Log.i("FNull?", e.toString());
                }

                //mAdapter.updateDataSet(myListItems);
            }
        };


        getData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View view) {
                employeesRefID = database.getReference("Employees").child(currentUser).child("Companies"); //SEE HOW ADD EMPLOYEES checks
                employeesRefID.addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {

                        callback.gotDataSnapshot(dataSnapshot);
                    }


                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                        Log.d("Cancelled", databaseError.toString());
                    }

                }); //END EMPLOYEE EVENT LISTENER
                Log.i("OutsideEvent", myCompanyIDsList.toString());

            }
        }); //END ONCLICK
        Log.i("OutsideonClick", myCompanyIDsList.toString());
    }


    interface DataSnapshotCallback {
        void gotDataSnapshot(DataSnapshot snapshot);
    }
}
ImTheNun
  • 167
  • 1
  • 10
  • "Should I run .getValue() on the fields and store them in another way?" That other way would also use memory. Unless it uses less memory than your custom class, you won't have gained anything. – Frank van Puffelen Feb 08 '18 at 17:34

1 Answers1

0

The trick to reducing memory usage when using Firebase is to only load data that you're going to display to the user.

If you need a list of just business names, create a nodes with just the business names in the database and display that. That way you've reduce both the bandwidth and the memory used, since you're not loading the other properties of the company.

You'll typically have one "master list" with all properties of each company (or other entity type). And then you may have one or more "display lists" that contain only the information of the business that you need to display in certain areas. This duplicated data is quite common in NoSQL databases, and is known as denormalization.

For a better introduction, read Denormalizing Your Data is Normal, NoSQL data modeling, and watch Firebase for SQL developers.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks Frank it's starting to come together. A few questions: So are you implying that querying the FirebaseDB more than once is fine as long as you structure it optimally (and is better than downloading many Snapshots into an ArrayList)? Also, in my example I would get rid of the "EmployeeIDs" and "ModeratorIDs" from the Companies Node? Thanks for the youtube series, as I do come from a SQL background and have been working on denormalizing my Firebase DB over the past week. – ImTheNun Feb 08 '18 at 23:40