Value of a global variable is reset after it is initialised in ValueEventListener

前端 未结 1 1752
暖寄归人
暖寄归人 2020-11-27 08:02

I have a global variable named \"bg\". It gets initialised inside the ValueEventListener of the firebase database reference \"myRef\"

But if I try to use the value

相关标签:
1条回答
  • 2020-11-27 08:38

    There is no magic going on here. You're just seeing the effects of asynchronous loading, on which most of the modern web is built.

    It's easiest to understand if you run the code in a debugger or add some logging statements, like this:

    FirebaseDatabase database = FirebaseDatabase.getInstance();
    DatabaseReference myRef = database.getReference(path);   
    
    System.out.println("Before adding listener");
    myRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            System.out.println("In onDataChange");
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {
            throw databaseError.toException();
        }
    });
    
    System.out.println("After adding listener");
    

    When you run the code like this, it will print:

    Before adding listener

    After adding listener

    In OnDataChange

    This is probably not what you expected, but it is the expected behavior when dealing with Firebase and as said most modern web APIs. Since loading the data may take an unknown amount of time (it has to be gotten from somewhere on the internet after all), the code doesn't wait for the data to be return, but instead simply continues with the line after you attached the listener. Then when the data becomes available, it calls your onDataChange() and you can use the data.

    This behavior is incredibly confusing at first, so don't worry if it's not immediately clear. The important thing to realize is that the behavior is normal and part of modern web programming. So don't try to work around it (i.e. making the code wait for the data). Instead: try to reframe your problem into a model that works better with this asynchronous nature.

    I found it easiest to reframe my problems from a "first load the data, then show it in a toast" to "start loading the data, then when it's loaded, show it in a toast". This translates to the following code:

    FirebaseDatabase database = FirebaseDatabase.getInstance();
    DatabaseReference myRef = database.getReference(path);   
    
    myRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            bg=dataSnapshot.getValue().toString();
            Toast.makeText(MapsActivity.this, bg, Toast.LENGTH_SHORT).show();  
        }
    
        @Override
        public void onCancelled(DatabaseError databaseError) {
            throw databaseError.toException();
        }
    });
    
    0 讨论(0)
提交回复
热议问题