在选项卡 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为了更好的理解。