Reputation: 51
I have a model class named Family in my project. I am creating the list of the that class. Firstly I instantiated the firebase database, then initialize the list. After that loadData() method is called to fill the list by collecting data from firebase. The list is getting updated there and when I checked the size inside the loadData() method, it is showing appropriate size but when I am checking the list outside the loadData() method it is showing list as empty. I am confused what I am missing here. Here is the code:
public class FamilyRecycler extends AppCompatActivity {
ArrayList<Family> list1;
ArrayList<Family> mylist;
private DatabaseReference mDatabase, demoRef;
DBHelper myDB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_family_recycler);
String id = getIntent().getExtras().getString("id");
String name="";
boolean flag = true;
mylist = new ArrayList<>();
mDatabase = FirebaseDatabase.getInstance().getReference("family");
loadData();
Toast.makeText(this, "Size: "+mylist.size(), Toast.LENGTH_SHORT).show();
list1 = new ArrayList<Family>();
myDB = new DBHelper(this);
while(hasParent(id)){
for(int i=0;i<mylist.size();i++){
if(mylist.get(i).getId().equalsIgnoreCase(id)){
list1.add(mylist.get(i));
id=mylist.get(i).getFid();
break;
}
}
}
this.setTitle(name+"'s Family Tree");
RecyclerView familyList = findViewById(R.id.familyList);
familyList.setLayoutManager(new LinearLayoutManager(this));
familyList.setAdapter(new FamilyAdapter(list1));
}
public void loadData(){
mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//List<Family> list = new ArrayList<>();
for (DataSnapshot adSnapshot: dataSnapshot.getChildren()) {
Family f = adSnapshot.getValue(Family.class);
mylist.add(f);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
public boolean hasParent(String id){
String fid="";
boolean status =false;
for(int i=0;i<mylist.size();i++)
{
Toast.makeText(this, "FID: "+mylist.get(i).getId(), Toast.LENGTH_SHORT).show();
if(Integer.parseInt(mylist.get(i).getId())==Integer.parseInt(id))
{
fid = mylist.get(i).getFid();
break;
}
}
for(int i=0; i<mylist.size();i++)
{
Toast.makeText(this, "Value "+status, Toast.LENGTH_SHORT).show();
if(Integer.parseInt(mylist.get(i).getId())==Integer.parseInt(fid)){
status= true;
break;
}
}
// Toast.makeText(this, "Status"+status+mylist.get(47).getId(), Toast.LENGTH_SHORT).show();
return status;
}
}
Do let me know, If more information is needed!
Upvotes: 1
Views: 937
Reputation: 680
you need to wait for response coming from firebase database. So, as per your app requirements, do the below changes in your code :
1) create one interface for getting response :
public interface GetFamilyData {
void onDataLoaded(ArrayList<Family> families);
void onError(String errorMsg);
}
2) now change the loadData() method like below :
public void loadData(final GetFamilyData familyData) {
mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//List<Family> list = new ArrayList<>();
for (DataSnapshot adSnapshot : dataSnapshot.getChildren()) {
Family f = adSnapshot.getValue(Family.class);
mylist.add(f);
}
familyData.onDataLoaded(mylist);
}
@Override
public void onCancelled(DatabaseError databaseError) {
familyData.onError("Error occur while getting family data");
}
});
}
3) now call your loadData() method :
loadData(new GetFamilyData() {
@Override
public void onDataLoaded(ArrayList<Family> families) {
Toast.makeText(FamilyRecycler.this, "Size: "+families.size(), Toast.LENGTH_SHORT).show();
list1 = new ArrayList<Family>();
myDB = new DBHelper(this);
while(hasParent(id)){
for(int i=0;i<families.size();i++){
if(families.get(i).getId().equalsIgnoreCase(id)){
list1.add(families.get(i));
id=families.get(i).getFid();
break;
}
}
}
FamilyRecycler.this.setTitle(name+"'s Family Tree");
RecyclerView familyList = findViewById(R.id.familyList);
familyList.setLayoutManager(new LinearLayoutManager(FamilyRecycler.this));
familyList.setAdapter(new FamilyAdapter(list1));
}
@Override
public void onError(String errorMsg) {
Toast.makeText(FamilyRecycler.this, errorMsg, Toast.LENGTH_SHORT).show();
}
});
hope this will work for you
Upvotes: 2
Reputation: 916
As Firebase realtime database works asynchronously (database queries and stuffs run on a background thread, therefore somehow your loadData() method is invoked after all other methods invoked inside onCreate() method. The solution is, you have to put all what you want to do with the retrieved data inside onDataChange() method, otherwise its not gonna work.
I have rewritten your code as follow:
public void loadData(){
mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Family> list = new ArrayList<>();
for (DataSnapshot adSnapshot: dataSnapshot.getChildren()) {
Family f = adSnapshot.getValue(Family.class);
list.add(f);
}
familyList.setAdapter(new FamilyAdapter(list));
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Upvotes: 1
Reputation: 76
As I know, onDataChange() method will be invoked asynchronously. That means when you show Toast about size of the list, at the time onDataChange() may not be invoked yet, so the list is empty.
You should put Toast code inside onDataChange() to see result
Upvotes: 1