El valor de una variable global se restablece después de inicializarse en ValueEventListener

Tengo una variable global llamada “bg”. Se inicializa dentro del ValueEventListener de la referencia de base de datos de firebase “myRef”

Pero si trato de usar el valor de la variable fuera del bloque valueeventlistener, la variable está vacía. Es como si se estuviera restableciendo.

Soy muy nuevo en Android. Por favor, hágame saber lo que está mal.

El código es el siguiente:

package com.example.tejasvi.donorfinder; import android.support.v4.app.FragmentActivity; import android.os.Bundle; import android.widget.Toast; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; public class MapsActivity extends FragmentActivity implements OnMapReadyCallback { private GoogleMap mMap; private FirebaseAuth mAuth; public String latlng[],bg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maps); mAuth = FirebaseAuth.getInstance(); Bundle bundle = getIntent().getExtras(); String s= bundle.getString("Phone"); String path="Active Requests/"+mAuth.getCurrentUser().getUid()+"/"+s+"/Blood Group"; FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference myRef = database.getReference(path); myRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { bg=dataSnapshot.getValue().toString(); } @Override public void onCancelled(DatabaseError databaseError) { Toast.makeText(MapsActivity.this, "Error", Toast.LENGTH_LONG).show(); } }); Toast.makeText(MapsActivity.this, bg, Toast.LENGTH_SHORT).show(); //bg is empty here SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; } } 

El valor de dataSnapshot.getValue () es “A + ve”

El archivo JSON es el siguiente:

 { "Active Requests": { "3R8XGIM5uSRv3sxQZ2sqqUnIjQ62": { "9849949799": { "Blood Group": "B+ve", "Date of Requirement": "3/1/17", "Direct or Replacement?": "Direct donation", "Donation Type": "Whole Blood", "For Self?": "Yes", "Hospital Name": "Shekhar Hospital", "Location": "12.945793000000002,77.56759339999999", "Name": "Poorna Chandra Tejasvi", "Units": "2" } }, "YL5oVxmua4gktNM2TwwPavL1Tj32": { "123456789": { "Blood Group": "A+ve", "Date of Requirement": "1/1/17", "Direct or Replacement?": "Direct donation", "Donation Type": "Whole Blood", "For Self?": "No", "Hospital Name": "Columbia Asia Hospital - Hebbal", "Location": "13.0509869,77.5937892", "Recipient Name": "jssnxn", "Recipient Relation": "Married", "Units": "3" } } } } 

No hay magia pasando aquí. Solo está viendo los efectos de la carga asincrónica, en la que se basa la mayoría de la web moderna.

Es más fácil de entender si ejecuta el código en un depurador o agrega algunas instrucciones de registro, como esta:

 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"); 

Cuando ejecuta el código de esta manera, imprimirá:

Antes de agregar oyente

Después de agregar oyente

En OnDataChange

Es probable que esto no sea lo que esperabas, pero es el comportamiento esperado al tratar con Firebase y, como dicen, las API web más modernas. Dado que cargar los datos puede tomar una cantidad de tiempo desconocida (debe obtenerse de algún lugar de Internet después de todo), el código no espera a que se devuelvan los datos, sino que simplemente continúa con la línea después de adjuntar el oyente. Luego, cuando los datos estén disponibles, llama a su onDataChange() y puede usar los datos.

Este comportamiento es increíblemente confuso al principio, así que no se preocupe si no está claro inmediatamente. Lo importante es darse cuenta de que el comportamiento es normal y parte de la progtwigción web moderna. Por lo tanto, no intente evitarlo (es decir, hacer que el código espere los datos). En cambio, intente replantear su problema en un modelo que funcione mejor con esta naturaleza asincrónica.

Me resultó más fácil replantear mis problemas desde “cargar los datos por primera vez, luego mostrarlos en un brindis” para “comenzar a cargar los datos, luego, cuando estén cargados, mostrarlos en un brindis”. Esto se traduce al siguiente código:

 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(); } });