0

I use Firebase DB as DB for my Android app. I need to check if db contains an object with a name, which gives user. If yes, I save the ref to it and load datas, esle - show info about incorrect name of object.

As exemple I used: Firebase querying data

Code:

private void setListReferance(){
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);

    builder.setTitle(Config.ADDLIST);

            // Set up the input
            final EditText input = new EditText(this);
            // Specify the type of input expected; this, for example, sets the input as a password, and will mask the text
            input.setInputType(InputType.TYPE_CLASS_TEXT);
            builder.setView(input);

            // Set up the buttons
            builder.setPositiveButton(Config.OK, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    String listName = input.getText().toString();
                    boolean correctName = checkListName(shoplistsRef, listName);

                    if(correctName){
                        listRef = shoplistsRef.child(listName);
                        myAdapter.setItemsListRef(listRef);
                        myAdapter.notifyDataSetChanged();
                        firebaseUpdate();
                    }
                    else{
                        String messege = "Niepoprawna nazwa listy";
                        Toast.makeText(MainActivity.this,
                                messege, Toast.LENGTH_LONG).show();
                    }
                }
            });
            builder.setNegativeButton(Config.CANCEL, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });

            builder.show();
}

Method which check if db contains. For tests I added toasts.

private boolean checkListName(DatabaseReference ref, String listName){
    boolean[] result = new boolean[1];
    Query query = ref.child(listName);

    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            if (dataSnapshot.exists()) {
                Toast.makeText(MainActivity.this,
                        ref.toString(), Toast.LENGTH_LONG).show();


                    Toast.makeText(MainActivity.this,
                            dataSnapshot.getValue(String.class), Toast.LENGTH_LONG).show();

                result[0] = true;
            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
    return result[0];
}

The problem is when I write correct name (DB has it) the first toast showed from else block setListReferance() (it should not be showed at all) and then two toasts from if (dataSnapshot.exists()){}

Why does it happend? I think there is a problem with sync and async methods but I don't know how to solve it.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • 1
    check answer given here https://stackoverflow.com/questions/34486417/firebase-offline-capabilities-and-addlistenerforsinglevalueevent ... – Amod Gokhale Jul 23 '18 at 16:25
  • You cannot set `result[0]` inside the `onDataChange()` method and then simply use it outside. So please check the duplicate to see why do you have this behaviour and how can you solve this using a custom callback. – Alex Mamo Jul 24 '18 at 09:24

1 Answers1

0

Firebase is an Asynchronous design. Peek at Google documentation Read and Write using Firebase

Firebase data is written to a FirebaseDatabase reference and retrieved by attaching an asynchronous listener to the reference. The listener is triggered once for the initial state of the data and again anytime the data changes.

doing this: "boolean[] result = new boolean1;" will not work because of the asynchronous implementation. sure sometimes you may get lucky for whatever reason and you'll see the value update but it's inconsistent. the reason is, you're declaring the value at the same time your packet races to the firebase database to get it's value, then this is where the chaos happens, the value is updated and then the packet arrives back but it's too late, the value was already updates.

One workaround to this would be to use a callback listener as such:

public class FireBaseHandler{
 private FirebaseDatabase mFirebaseDatabase;
 private DatabaseReference mFireBaseReference;
 private long firebaseKeyCount;

 public FireBaseHandler(){
  mFirebaseDatabase = FirebaseDatabase.getInstance();
  mFireBaseReference = mFirebaseDatabase.getReference();
  firebaseKeyCount = 0;
 }

 public void readAllKeysFireBase(final OnFireBaseListener listener){
 mFireBaseReference.addValueEventListener(new ValueEventListener() {
  @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
   for(DataSnapshot snapshot : dataSnapshot.getChildren()) {
    for(DataSnapshot key : snapshot.getChildren()){
     Log.d("getKeys(): ", key.getKey()); //gets the keys from firebase
     firebaseKeyCount = listener.keyCount(key.getChildrenCount());
    }//foreach_snapshot
   }//foreach_dataSnapshot
  }//onDataChange
  @Override public void onCancelled(@NonNull DatabaseError databaseError) {
   Log.w("onCancelled()", "Failed to read value.", databaseError.toException());
  }//onCancelled
 });//mFireBaseReference
}//readAllKeysFireBase
}//FireBaseHandler end of class

public interface OnFireBaseListener{
 long keyCount(long data);
}
EvOlaNdLuPiZ
  • 600
  • 1
  • 4
  • 21