Andy
Andy

Reputation: 151

Android Firebase Retrieving Data Synchronized and "returning" it

I'm sorry if this may seem like a stupid question, but I haven't found any similar questions around so here goes.

I have a class DatabaseService for retrieving data(Animal) from the Firebase Realtime-Database. From a previous post I've learned that because these API calls are asynchronous, one should create an Interface in order to sync the retrieval of data ( the onDataChange() method )

My questions are:

  1. why does creating this interface and passing it as a parameter work for synchronizing data retrieval? In my code , why does calling the interfaces' method onCallBack (which isn't even defined until later) make it happen, what are the steps that take place to make it happen?
  2. Having created this class as a database service (hence the name), I want it to return a list of animals ( List ) for the Activity that containts this service, MyAnimalsActivity , in order to make a RecyclerView. Is there any way I can change the "void" in this Interface method to "List" to have something like

    List<Animal> listAnimals = databaseService.readData(); 
    

    or should this entire DatabaseService class rather be removed and add its' code in the MyAnimalsActivity itself, in order to add the Animals Objects inside a global list in the onDataChange() method?

DatabaseService:

public class DatabaseService {

    private FirebaseDatabase firebaseDatabase;
    private DatabaseReference firebaseRootRef;
    private DatabaseReference animalsRef;
    List<Animal> animalsList;

    public DatabaseService() {

        this.firebaseDatabase = FirebaseDatabase.getInstance();
        this.firebaseRootRef = firebaseDatabase.getReference();
        this.animalsRef = firebaseDatabase.getReference("animals");

        animalsList = new ArrayList<>();
    }


    private interface FirebaseCallback {
        void onCallback(List<Animal> list);
    }

    public void readItemsFromDatabase(final FirebaseCallback firebaseCallback) {

        ValueEventListener valueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                animalsList.clear();

                //dataSnapshot.getChildren() ---> iterate through entire dataSnapshot Object, to get the items names
                for(DataSnapshot ds : dataSnapshot.getChildren()) {
                    Animal animal;
                    animal = ds.getValue(Animal.class);
                    animalsList.add(animal);
                }

                firebaseCallback.onCallback(animalsList);

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                Log.d("DATABASE_TAG", databaseError.getMessage());
            }
        };

        animalsRef.addValueEventListener(valueEventListener);

    }


    public void readData() {
        readItemsFromDatabase(new FirebaseCallback() {
            @Override
            public void onCallback(List<Animal> list) {
                Log.d("DATABASE_TAG", list.toString());
            }
        });
    }

}

MyAnimalsActivity :

public class MyAnimalsActivity extends AppCompatActivity {

private RecyclerView recyclerView;
private RecyclerView.Adapter animalAdapter;

private List<Animal> listAnimals;

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

    DatabaseService databaseService = new DatabaseService();
    databaseService.readData();


    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    recyclerView.setHasFixedSize(true); //every item of the recyclerview has a fixed size;
    recyclerView.setLayoutManager(new LinearLayoutManager(this));

    listAnimals = new ArrayList<>();
    //listAnimals  =  databaseService.readData();  ??


}
}

Upvotes: 0

Views: 355

Answers (1)

Gast&#243;n Saill&#233;n
Gast&#243;n Saill&#233;n

Reputation: 13129

Writing a method that returns an asynchronous value that might be not there can cause NullPointers if you call it before it has the data.

To make this simple, since the method readItemsFromDatabase is public, you can call it from your MyAnimalsActivity and get your data from there.

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

    DatabaseService databaseService = new DatabaseService();
    databaseService.readItemsFromDatabase(new DatabaseService.FirebaseCallback() {
            @Override
            public void onCallback(List<Animal> list) {
                Log.d("DATABASE_TAG", list.toString());

            }
        });
...

I have isolated your issue with a project of mine and it's working; also, you can check the MVP pattern that will solve all these issues for you and your code will become cleaner.

Upvotes: 2

Related Questions