Value of a Global Variable Is Reset After It Is Initialised in Valueeventlistener

Assigning value to a global variable from FirebaseDatabase

You cannot simply create a global variable and use it's value outside the onDataChange() because this methos has an asynchronous behaviour. If you want to use a value that is coming from the database outside the onDataChange() method, you have two choices. The first one would be to pass the desired object as argument to a method that is defined in your class or, if you want it in a more complex way, then dive into the asynchronous world of modern API's and see the last part of my answer in this post, in which I have explained step by step how you can achieve this. For more information, you can take also a look at this video.

Edit:

databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
StateDetails stateDetails = dataSnapshot.getValue(StateDetails.class);
methodThatDoesSomething(stateDetails); //Method call

}

@Override
public void onCancelled(DatabaseError databaseError) {}
});

private void methodThatDoesSomething(StateDetails stateDetails) {
//Do what you need to do with your stateDetails object
}

Function addListenerForSingleValueEvent from firebase

All data reading in Firebase happens asynchronously, so I recommend you change your code to something that looks like this:

private void checkAlreadyRegistered(){

/*Get the reference*/
mDatabaseReference = FirebaseDatabase.getInstance().getReference("Users/" + childDetails.getPhone() + "/" + childDetails.getPatientName());
mDatabaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(TAG, "onDataChange: " + dataSnapshot);
if (dataSnapshot.getValue() != null) {

AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Record Already Exists");
builder.setMessage("The current patient is already registered");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
resetRegisterFields();
}
});
builder.create();
builder.show();
}
else
{
saveInDatabase(patient_id); //TODO change this accordingly
}
}

@Override
public void onCancelled(DatabaseError databaseError) {

Toast.makeText(getContext(), "Some error occured", Toast.LENGTH_LONG).show();
}
});
}

And your save method:

void saveInDatabase(Long patient_id) {
mDatabaseReference = FirebaseDatabase.getInstance().getReference("Current_registered_users");
mDatabaseReference.setValue(patient_id + 1);
childDetails.setPatient_id(patient_id);
mDatabaseReference = FirebaseDatabase.getInstance().getReference("Users");
Log.d(TAG, "saveInDatabase: "+mDatabaseReference);
mDatabaseReference.child(childDetails.getPhone()).child(childDetails.getPatientName()).child("Registration Details").setValue(childDetails);
Button bt = (Button) getView().findViewById(R.id.buttonRegister);
resetRegisterFields();
progressDialog.dismiss();
displayPid(patient_id);
bt.setEnabled(true);
.
.
}

Retrieve String out of addValueEventListener Firebase

The data is loaded from Firebase asynchronously. By the time you run title = a, the onDataChange method hasn't been called yet. Set some breakpoints in a debugger to verify this, it's key to understanding how asynchronous loading works.

The solution is to reframe your problem from "first get the object, then do blabla with the title" to "start getting the object; once the object is available, do blabla with the title".

In code this translates to:

final DatabaseReference mPostReference = FirebaseDatabase.getInstance().getReference().child("user-daily").child(getUid()).child("2017-Year");
mPostReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
final ArrayList<String> labels = new ArrayList<String>();
for (DataSnapshot data : dataSnapshot.getChildren()){
final DailyItem dailyItem = data.getValue(DailyItem.class);
labels.add(dailyItem.mese);

}
title.setText(labels.get(position));

// Do blabla with the title
String title = title.getText().toString();
}

@Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(view.getContext(),"database error",
Toast.LENGTH_SHORT).show();
}
});

Many developers new to Firebase (and other modern web APIs, as they all work this way) struggle with this problem. So I recommend you also check out their questions and answers:

  • Cannot access firebaseObjectObservable outside of set
  • Android Firebase get value of child without DataChange
  • Value of a global variable is reset after it is initialised in ValueEventListener
  • can't get values out of ondatachange method
  • ArrayList not updating inside onChildAdded function
  • Setting Singleton property value in Firebase Listener
  • and most others in this list of search results

Return value from valueEventListener java

As with all async operations I often do it in a callback manner.

Your solution could work like this:

  1. Create a simple callback interface (I have mine in a library that I use in almost every app)

    public interface SimpleCallback {
    void callback(Object data);
    }

    // You could do it as well generic, that's what I do in my lib:
    public interface SimpleCallback<T> {
    void callback(T data);
    }

Then redesign the signature of your method like this:

private void checkAnswerSubmission(@NonNull SimpleCallback<boolean> finishedCallback) {

DatabaseReference answerDatabase = FirebaseDatabase.getInstance().getReference().child("userPuzzleHistory").child(uid);
answerDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This will simple call your callback containing a boolean true/false
finishedCallback.callback(dataSnapshot.hasChild(String.valueOf(imagename)));
}

@Override
public void onCancelled(DatabaseError databaseError) {

}
});
}

You call this with:

checkAnswerSubmission(new SimpleCallback<boolean>() {
@Override
void callback(boolean data) {
if (data) {
// true was returned
} else {
// false was returned
}
}
});

onDataChange calling abrupt

If you are sure that the code has no errors, I would like to remind you that Firebase connections are async. That said, you can not use an async method to return a value, because the return sentence is going to be executed before you have enough time to change that boolean.

Try changing the method so it returns void and inside onDataChange use a kind of response method with the value.

Example:

private void authenticateUser(final String role, final String userId) {
DatabaseReference roleReference = FirebaseDatabase.getInstance().getReference().child("role").child(role);
roleReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
HashMap<String, String> map = (HashMap<String, String>) dataSnapshot.getValue();
if (map != null) {
Set<String> userIds = map.keySet();
if (userIds.contains(userId))
authenticationResult = true;
}
authenticateUserResponse(authenticationResult);
}

@Override
public void onCancelled(DatabaseError databaseError) {

}
});

That will be the only way to do it properly, since async methods are not meant to return values before the job was done.

Why Global variable does not update with global function within the same Global variable? Android/Java

In your code, the constant GET_CART_ALL_ITEM is created and initialize only one time, and it takes the current value of ReturnUserRrQuote(). Later It will not trigger the function as the constant already has its value and does not require a new initialization.

If at the beginning of code ReturnUserRrQuote() => "100". Then GET_CART_ALL_ITEM is created and initialize with this value, it will be "store/3/cart/100/type/customer" and not "store/3/cart/" + ReturnUserRrQuote() + "/type/customer". It's due cause at initialization the expression "store/3/cart/" + ReturnUserRrQuote() + "/type/customer" is evaluated and the result is affected to the constant (the expression is not affected to the constant).

So when you call this constant later, with supposed ReturnUserRrQuote() => "250". GET_CART_ALL_ITEM still is "store/3/cart/100/type/customer". You haven't redefine it to contain the new value of ReturnUserRrQuote() (And you don't want java to do so or it won't be a constant).

In your case either you want a constant so it's normal that it don't change whenever ReturnUserRrQuote() changes. Or you want it to re-evaluate at every time and you do not want a constant. You could do something like :

public static final const1 = "store/3/cart/";
public static final const2 = "/type/customer";

//whenever you have to obtain your value
String value = const1 + ReturnUserRrQuote() + const2;

Edit:
You speak about global variable and not constant but the problem is the same. Even with non global variable.

//Static function that return the number of times it has been called
public static returnNumber() {
final int i=1;
return i++;
}

public static void main() {
int a = returnNumber(); //Initialize a
for (j=0; j<10; j++) {
System.out.println(a); //print the current value of a
}
}

In this example, a will be initialize at the beginning of main. the expression returnNumber() will be evaluated and the result will be affected to a. Here it's the first call to returnNumber then the result is 1. So the value of a is 1 and not returnNumber(). In the loop I call a 10 times and I print it. The 10 times a will value 1 and the number 1 will be printed 10 times. It does not call returnNumber() every time I call a.



Related Topics



Leave a reply



Submit