allen1124
allen1124

Reputation: 25

List size goes back to zero for some reason

I am loading data from cloud firestore into a custom recyclerview adapter. According to my log I get the data from firestore just fine and inside of my get method the log shows my list size increasing. Outside of my get method mWorkoutList goes back to size 0. I cannot figure out why this is happening.Log shows mWorkoutList size going back to 0

public class ViewWorkoutsActivity extends AppCompatActivity implements WorkoutAdapter.WorkoutAdapterOnClickHandler {

private final String TAG = this.getClass().getName();
private FirebaseFirestore db;
private String mUid;
private List<Set> mSetList;
private RecyclerView mRecyclerView;
private WorkoutAdapter mWorkoutAdapter;
private List<OtherWorkout> mWorkoutList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_view_workouts);
    mWorkoutList = new ArrayList<>();
    mUid = getIntent().getStringExtra("uid");
    db = FirebaseFirestore.getInstance();
    initDatabaseData();

    mRecyclerView = findViewById(R.id.recycler_view);

    LinearLayoutManager linearLayoutManager
            = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    mRecyclerView.setLayoutManager(linearLayoutManager);
    mRecyclerView.setHasFixedSize(true);
    mWorkoutAdapter = new WorkoutAdapter(this);
    mRecyclerView.setAdapter(mWorkoutAdapter);
    Log.i("LOG", "workout list size HERE: " + mWorkoutList.size());
    mWorkoutAdapter.setWorkoutData(mWorkoutList);
}

@Override
public void onClick(OtherWorkout workout) {

}

public void initDatabaseData(){
    CollectionReference collectionReference2 = db.collection("users").document(mUid).collection("workouts");
    collectionReference2.get()
            .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                @Override
                public void onComplete(@NonNull Task<QuerySnapshot> task) {
                    if(task.isSuccessful()){
                        for (QueryDocumentSnapshot document : task.getResult()){
                            OtherWorkout workout = document.toObject(OtherWorkout.class);
                            mWorkoutList.add(workout);
                            Log.i("LOG", "workout list size: " + mWorkoutList.size());
                        }
                    }
                }
            });
}
}

Upvotes: 0

Views: 224

Answers (4)

jhamon
jhamon

Reputation: 3691

addOnCompleteListener provides a way to add asynchronous task listener.

When you call initDatabaseData(), you start the task and define a listener. But there is no guarantee that this task is completed when returning from initDatabaseData.

That's why, once you print mWorkoutList size in the onCreate method, the value can be different from the one printed in the listener.

To avoid that, you can change the way your program works either by changing the async mechanism to a sync one, or by the part using the data to the listener onComplete method

Upvotes: 0

Afzal Khan
Afzal Khan

Reputation: 346

Hi Allen you are calling initDatabaseData(); in oncreate() method which is making Network Request and fetching data. So it takes roughly around 2-3 seconds to fetch the data. But In that 2-3 seconds your code below initDatabaseData() getting called

 LinearLayoutManager linearLayoutManager
        = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(linearLayoutManager);
mRecyclerView.setHasFixedSize(true);
mWorkoutAdapter = new WorkoutAdapter(this);
mRecyclerView.setAdapter(mWorkoutAdapter);
Log.i("LOG", "workout list size HERE: " + mWorkoutList.size());
mWorkoutAdapter.setWorkoutData(mWorkoutList);

So till the data has not come the listsize will display 0 and then after you get the data in onComplete() list size will increase(). So basically add a line mWorkoutAdapter.notifyDatasetChanged(); here:-

if(task.isSuccessful()){
                    for (QueryDocumentSnapshot document : task.getResult()){
                        OtherWorkout workout = document.toObject(OtherWorkout.class);
                        mWorkoutList.add(workout);
                        Log.i("LOG", "workout list size: " + mWorkoutList.size());
                    }mWorkoutAdapter.notifyDatasetChanged();

                }

This will refresh your Adapter with your new values.

Upvotes: 2

Avinash
Avinash

Reputation: 897

You can check your

  Log.i("LOG", "workout list size: " + mWorkoutList.size());

after

 Log.i("LOG", "workout list size HERE: " + mWorkoutList.size());

so it means firebase take some some time for fetch all data , in period of this time your rest of code are executed. so the solution is called initDatabaseData() after set the adapter then adapter.notifydatasetchanged() called. or you can direct notify the adapter in initDatabaseData() method after fetching data.

Upvotes: 0

paradx
paradx

Reputation: 74

You create OtherWorkout as a local object, then add it to the collection. If your get() function runs out of scope the object will be automatically deleted.

I didn't check but I think the Java garbage collection will take care of the rest and delete the object from the Array.

You should create the objects on the Heap with new so they will persist outside of the scope of that function.

Upvotes: 0

Related Questions