在选项卡 activity 中,从 Firebase 检索数据效果不佳
In tabbed activity, retrive data from Firebase doesn't work well
在下面的代码中,我尝试从 Firebase 读取数据,并使用它来动态创建卡片视图,但是当程序启动时,当我单击第三个选项卡并返回到第一个选项卡时,ArrayList 为空。找出问题几天后,我无法自己解决这个问题。
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());
}
}*/
}
当您循环 m2.jaratok
时,数据仍然不可用,这就是您的列表为空的原因。 Firebase API 是 asynchronous
,这意味着 onDataChange()
方法 returns 在它被调用后立即被调用,并且它 returns 的任务回调将在某个时间被调用稍后。
无法保证需要多长时间,可能需要几百毫秒到几秒才能获得数据并可以使用。因为那个方法 returns 立即,你试图在回调之外使用它的 jaratok
列表是空的。
基本上,您正在尝试从异步的 API 中同步使用一个值。那不是一个好主意。您应该按预期异步处理 APIs。
一个快速解决这个问题的方法是只在 onDataChange()
方法中使用 jaratok
列表,否则我建议你从这个 in which I have explained how it can be done using a custom callback. You can also take a look at this video为了更好的理解。
在下面的代码中,我尝试从 Firebase 读取数据,并使用它来动态创建卡片视图,但是当程序启动时,当我单击第三个选项卡并返回到第一个选项卡时,ArrayList 为空。找出问题几天后,我无法自己解决这个问题。 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());
}
}*/
}
当您循环 m2.jaratok
时,数据仍然不可用,这就是您的列表为空的原因。 Firebase API 是 asynchronous
,这意味着 onDataChange()
方法 returns 在它被调用后立即被调用,并且它 returns 的任务回调将在某个时间被调用稍后。
无法保证需要多长时间,可能需要几百毫秒到几秒才能获得数据并可以使用。因为那个方法 returns 立即,你试图在回调之外使用它的 jaratok
列表是空的。
基本上,您正在尝试从异步的 API 中同步使用一个值。那不是一个好主意。您应该按预期异步处理 APIs。
一个快速解决这个问题的方法是只在 onDataChange()
方法中使用 jaratok
列表,否则我建议你从这个