0

This function is returning no data in spite of receiving snapshots and adding the data in ArrayList in onDataChange() function but in the end, it is returning ArrayList with size 0.

List<ProductEntity> feed_data() {
        final List<ProductEntity> feededProducts = new ArrayList<>();

    progressDialog = new ProgressDialog(this);
    progressDialog.setMessage("Please wait...");
    progressDialog.show();
    mDatabase = FirebaseDatabase.getInstance().getReference("/products");

    //adding an event listener to fetch values
    mDatabase.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            //dismissing the progress dialog
            progressDialog.dismiss();

            //iterating through all the values in database
            for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                ProductEntity upload = postSnapshot.getValue(ProductEntity.class);
                Log.d("error", "onDataChange: " + upload.about);
                feededProducts.add(upload);
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d("Error", "onCancelled: " + databaseError.getMessage());

            NestedScrollView root_layout = findViewById(R.id.category_root_layout) ;
            Snackbar.make(root_layout, "Internal Error!!", Snackbar.LENGTH_SHORT).show();
        }
    });
    return feededProducts ;
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Rahul Mishra
  • 583
  • 7
  • 17
  • Data is loaded from Firebase asynchronously. You cannot return data from a function that hasn't been loaded yet. For a good introduction, see my answer here: https://stackoverflow.com/questions/33203379/setting-singleton-property-value-in-firebase-listener – Frank van Puffelen Nov 10 '17 at 13:06
  • check the permissions : https://stackoverflow.com/a/53433940/1308990 – oiyio Nov 22 '18 at 15:21

3 Answers3

3

onDataChange(DataSnapshot snapshot) is called asynchrounously. That is will be called when we get data back from Firebase.

Hence your return feededProducts is called before onDataChange(DataSnapshot snapshot) method, so you will be returning empty list everytime.

You will have to call notifydatasetchanged on your adapter inside onDataChange(DataSnapshot snapshot)

Ragesh Ramesh
  • 3,470
  • 2
  • 14
  • 20
  • can you please tell me the exact syntax of what i should write there. I am new to this. Thanks a lot for your help! – Rahul Mishra Nov 10 '17 at 09:16
  • No I tried that. But calling notifydatasetchanged is firing other errors in adpaters. How can I make it call asynchrounously and notify itself! – Rahul Mishra Nov 10 '17 at 09:22
1

You'll need to create an interface which you will call when the data is received.

interface DataReceivedListener{
    void onDataReceived(List<ProductEntity> data);
}

void feed_data(DataReceivedListener listener) {
    final List<ProductEntity> feededProducts = new ArrayList<>();

    progressDialog = new ProgressDialog(this);
    progressDialog.setMessage("Please wait...");
    progressDialog.show();
    mDatabase = FirebaseDatabase.getInstance().getReference("/products");

    //adding an event listener to fetch values
    mDatabase.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot snapshot) {
            //dismissing the progress dialog
            progressDialog.dismiss();

            //iterating through all the values in database
            for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                ProductEntity upload = 
                postSnapshot.getValue(ProductEntity.class);
                Log.d("error", "onDataChange: " + upload.about);
                feededProducts.add(upload);
            }

            listener.onDataReceived(feededProducts);

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d("Error", "onCancelled: " + databaseError.getMessage());

            NestedScrollView root_layout = 
            findViewById(R.id.category_root_layout) ;
            Snackbar.make(root_layout, "Internal Error!!", 
            Snackbar.LENGTH_SHORT).show();
        }
    });
}

Either implement the DataReceivedListener interface in your Activty and override the 'onDataReceived()' function and pass 'this' to 'feed_data(DataReceivedListener listener)' or create a DataReceivedListener as a variable and pass that variable to 'feed_data(DataReceivedListener listener)'

When the data is received in 'onDataChange(DataSnapshot snapshot)' it calls the function of the interface and then your overridden function will be called or the one you initilazied the 'DataReceivedListener' variable with. Depends on how you did it.

Put your code where you need the data inside the 'onDataReceived(List data)' function.

1

I just needed to initialize and set the Adapter after adding all the data in my Arralist as pointed out above like this and it solved my problem:

mDatabase.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot snapshot) {

                for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                    ProductEntity upload = postSnapshot.getValue(ProductEntity.class);
                    productList.add(upload);
                }

                productsRecyclerAdapter = new ProductsRecyclerAdapter(productList, CategoryActivity.this);
                products.setAdapter(productsRecyclerAdapter);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                NestedScrollView root_layout = findViewById(R.id.category_root_layout);
                Snackbar.make(root_layout, "Internal Error!!", Snackbar.LENGTH_SHORT).show();
            }
        });
Rahul Mishra
  • 583
  • 7
  • 17