Arraylist error index out of bound or it is null

Tags: , , ,



As we know there is no multi query option to firebase realtime database, so instead of using default FirebaseRecycler methods I am trying to manually feed keys from arraylist to the recycler view. In order to sort specific keys on the basis specific child nodes of the given parent I wrote below logic.

If I try to individually log the keys in if statement it shows displays all the sorted keys.

But now my problem is whenever I try to log the arraylist after fetching the values it shows null and if I log specific value at some index below error shows up.

public class categorizedProducts extends AppCompatActivity {

    private String catKey;
    private DatabaseReference productRef, catRef;
    private ArrayList<String> keyVal = new ArrayList<>();
    private long count = 0;
    private long i = 0;

   
    private void queryLogic(final String catTitle) {

        productRef.orderByChild("count").addValueEventListener(new ValueEventListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                count = dataSnapshot.getChildrenCount();

                for (final DataSnapshot snap: dataSnapshot.getChildren()){

                    productRef.child(Objects.requireNonNull(snap.getKey())).addValueEventListener(new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                            if (Objects.requireNonNull(dataSnapshot.child("category").getValue()).toString().equals(catTitle)) {

                                //keyVals.add(snap.getKey());
                                keyVal.add(snap.getKey());
                                i++;

                            }

                        }

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

                        }
                    });

                }

            }

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

            }
        });

    }
    // I am trying to log my arraylist here after retrieving the required keys from database

}


2020-06-27 19:50:32.315 567-567/com.kalpana.mortoys E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.kalpana.mortoys, PID: 567
    java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
        at java.util.ArrayList.get(ArrayList.java:437)
        at com.kalpana.mortoys.categorizedProducts$1.onDataChange(categorizedProducts.java:65)
        at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@19.2.1:75)
        at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@19.2.1:63)
        at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@19.2.1:55)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7397)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

I temporarily solved my error using this

public class categorizedProducts extends AppCompatActivity {

    private String catKey;
    private DatabaseReference productRef, catRef;
    private ArrayList<String> keyVal = new ArrayList<>();

    private long count = 0, i = 0;


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

        initFields();

        try {
            Bundle bundle = getIntent().getExtras();
            assert bundle != null;
            catKey = bundle.getString("key");

            assert catKey != null;
            catRef.child(catKey).addValueEventListener(new ValueEventListener() {
                @RequiresApi(api = Build.VERSION_CODES.KITKAT)
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {


                    queryLogic(Objects.requireNonNull(dataSnapshot.child("catTitle").getValue()).toString());

                }

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

                }
            });


        }
        catch (NullPointerException e) {

            e.printStackTrace();

        }

    }

    private void initFields() {

        productRef = FirebaseDatabase.getInstance().getReference().child("products");
        catRef = FirebaseDatabase.getInstance().getReference().child("categories");

    }

    @Override
    protected void onStart() {
        super.onStart();


        if (i == count) {

            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {

                    Log.i("TAG", "onStart: " + keyVal);

                }
            }, 3000);


        }

    }

    private void queryLogic(final String catTitle) {

        productRef.orderByChild("count").addValueEventListener(new ValueEventListener() {
            @RequiresApi(api = Build.VERSION_CODES.KITKAT)
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                count = dataSnapshot.getChildrenCount();

                for (final DataSnapshot snap: dataSnapshot.getChildren()){


                    i++;

                    productRef.child(Objects.requireNonNull(snap.getKey())).addValueEventListener(new ValueEventListener() {
                        @Override
                        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                            if (Objects.requireNonNull(dataSnapshot.child("category").getValue()).toString().equals(catTitle)) {

                                //keyVals.add(snap.getKey());
                                keyVal.add(snap.getKey());

                                //Log.i("TAG", "onDataChange: " + i);

                            }

                        }

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

                        }
                    });

                }

            }

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

            }
        });

    }

}

but still need an perfect solution

Answer

You could use a callback interface:

interface CallBack {public void done()}

and call queryLogic() as

queryLogic(catTitle,new CallBack() {
    public void done() {
        //log your arrayList here
    }
});

private void queryLogic (final String catTitle,final CallBack callBack){..}

and after the iteration is over just call the method callBack.done().



Source: stackoverflow