In the following code I tried to read data from Firebase, and use this to create dynamically cardviews, but when the program starts, the ArrayList is empty while I click on the third tab, and back to the first. After a few days of finding out the problem, I couldn't solve this by myself. MainScreen.java:
public class MainScreen extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
private static final String TAG = "MainScreen";
public List<BusNumber> jaratok= new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_screen);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.getTabAt(0).setText("Járatok");
tabLayout.getTabAt(1).setText("Megállók");
tabLayout.getTabAt(2).setText("Tervező");
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("bus_number");
myRef.addValueEventListener((new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
jaratok = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
jaratok.add(new BusNumber(ds.child("CodeNumber").getValue(String.class),ds.child("BusRouteName").getValue(String.class)));
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
Log.w("TAG","Failed to read data.",databaseError.toException());
}
}));
mSectionsPagerAdapter.notifyDataSetChanged();
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Fejlesztés alatt", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch(position)
{
case 0:
JaratokTab1 tab1 = new JaratokTab1();
return tab1;
case 1:
MegallokTab2 tab2 = new MegallokTab2();
return tab2;
case 2:
TervezoTab3 tab3 = new TervezoTab3();
return tab3;
default:
return null;
}
}
}
JaratokTab1.java:
public class JaratokTab1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.jaratok_tab1, container, false);
MainScreen m2 = (MainScreen) getActivity();
for (BusNumber n : m2.jaratok) {
Log.d("Ertek: ", n.getName());
}
CardView cardView = new CardView(getContext());
TextView tv = new TextView(getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(params);
cardView.setLayoutParams(params);
cardView.setVisibility(View.VISIBLE);
cardView.setCardElevation(9);
cardView.setPadding(15, 15, 15, 15);
cardView.setRadius(9);
tv.setTextColor(Color.RED);
tv.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
cardView.addView(tv);
LinearLayout linearLayout = rootView.findViewById(R.id.linearID);
linearLayout.setPadding(60,15,50,30);
linearLayout.addView(cardView);
return rootView;
}
//also tried this:
/* @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
MainScreen m2 = (MainScreen) getActivity();
for (BusNumber n : m2.jaratok) {
Log.d("Ertek: ", n.getName());
}
}*/
}
By the time you are looping through m2.jaratok
, the data isn't still available and that's why your list is empty. Firebase APIs are asynchronous
, meaning that onDataChange()
method returns immediately after it's invoked, and the callback from the Task it returns, will be called some time later.
There is no guarantee about how long it will take, it may take from a few hundred milliseconds to a few seconds before that data is available and can be used. Because that method returns immediately, your jaratok
list you're trying to use it outside the callback is empty.
Basically, you're trying use a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended.
A quick solve for this problem would be to use jaratok
list only inside the onDataChange()
method, otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.