且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Android - 从Firebase数据库显示ListView中的数据

更新时间:2022-10-15 07:42:31

数据是从Firebase数据库异步检索(并同步)到您的应用程序的。这意味着您的 sectionDetailsArrayList 可能随时被修改。当你修改数据时,你需要告诉适配器,以便它可以更新视图。

  private void fetchData (DataSnapshot dataSnapshot){
sectionDetailsArrayList.clear();

SectionDetails sectionDetails = dataSnapshot.getValue(SectionDetails.class);
sectionDetailsArrayList.add(sectionDetails);

//告诉适配器我们更改了它的数据
adapter.notifyDataSetChanged();
}

这应该更新视图。但是,由于您清除了每个被添加或更改的孩子的列表,因此该应用只会显示最新添加/修改的项目。



在Firebase中设置同步数组是有点牵扯的,因为你必须处理所有的事件类型,事实上evens可以以任何顺序发生。因此,我们创建了 FirebaseUI库,其中包含从Firebase数据库到ListView的适配器和RecyclerView


I have a custom listview to display data from Firebase database.

SectionDetails model

public class SectionDetails {
    private String sectionCode;
    private String sectionSeats;

public SectionDetails() {
}

public SectionDetails(String sectionCode, String sectionSeats) {
    this.sectionCode = sectionCode;
    this.sectionSeats = sectionSeats;
}

public String getSectionCode() {
    return sectionCode;
}

public String getSectionSeats() {
    return sectionSeats;
}

public void setSectionCode(String sectionCode) {
    this.sectionCode = sectionCode;
}

public void setSectionSeats(String sectionSeats) {
    this.sectionSeats = sectionSeats;
}
}

FirebaseHelper class

public class FirebaseHelper {
        DatabaseReference db;
        Boolean saved;
        ArrayList<SectionDetails> sectionDetailsArrayList = new ArrayList<>();

    public FirebaseHelper(DatabaseReference db) {
        this.db = db;
    }

    public Boolean save(SectionDetails sectionDetails) {

        if (sectionDetails == null) {
            saved = false;
        } else {
            try {
                db.push().setValue(sectionDetails);
                saved = true;

                adapter.notifyDataSetChanged();

            } catch(DatabaseException e) {
                e.printStackTrace();
                saved = false;
            }
        }

        return saved;
    }

    private void fetchData(DataSnapshot dataSnapshot) {
        sectionDetailsArrayList.clear();

        SectionDetails sectionDetails = dataSnapshot.getValue(SectionDetails.class);
        sectionDetailsArrayList.add(sectionDetails);
    }

    public ArrayList<SectionDetails> retrieve() {
        db.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                fetchData(dataSnapshot);
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });
        return sectionDetailsArrayList;
    }
}

CustomAdapter class

public class CustomAdapter extends BaseAdapter {
        Context c;
        ArrayList<SectionDetails> sectionDetailsArrayList;

    public CustomAdapter(Context c, ArrayList<SectionDetails> sectionDetailsArrayList) {
        this.c = c;
        this.sectionDetailsArrayList = sectionDetailsArrayList;
    }

    @Override
    public int getCount() {
        return sectionDetailsArrayList.size();
    }

    @Override
    public Object getItem(int position) {
        return sectionDetailsArrayList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(c).inflate(R.layout.sections_custom_listview, parent, false);
        }

        TextView lvTvSectionCode = (TextView) convertView.findViewById(R.id.lvTvSectionCode);
        TextView lvTvSectionSeats = (TextView) convertView.findViewById(R.id.lvTvSectionSeats);

        final SectionDetails sd = (SectionDetails) this.getItem(position);

        lvTvSectionCode.setText(sd.getSectionCode());
        lvTvSectionSeats.setText("allocated seats: " + sd.getSectionSeats());

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(c, sd.getSectionCode(), Toast.LENGTH_LONG).show();
            }
        });

        return convertView;
    }
}

MainActivity class

public class AddSection extends AppCompatActivity implements View.OnClickListener {

DatabaseReference mRef;
FirebaseHelper helper;
CustomAdapter adapter;
Button btnCreateSection;
ListView lvSectionsListOne;
String getFullSection, seats;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add_section);

    lvSectionsListOne = (ListView) findViewById(R.id.lvSectionsList);

    mRef = FirebaseDatabase.getInstance().getReference().child(Constants.FIREBASE_COURSES).child("sections");
    helper = new FirebaseHelper(mRef);

    adapter = new CustomAdapter(this, helper.retrieve());
    lvSectionsListOne.setAdapter(adapter);

    btnCreateSection = (Button) findViewById(R.id.btnCreateSection);
    btnCreateSection.setOnClickListener(this);

}

@Override
public void onClick(View v) {
    if (v == btnCreateSection) {

        getFullSection = "section 1A";
        seats = "20";

        SectionDetails sectionDetails = new SectionDetails(getFullSection, seats);

            if (helper.save(sectionDetails)) {

                adapter = new CustomAdapter(AddSection.this, helper.retrieve());
                lvSectionsListOne.setAdapter(adapter);

                adapter.notifyDataSetChanged();

            }
    }
}
}

I posted a similar question here, but this problem is different. When first data is added, nothing is shown in the listview. When second data is added, first data is shown in listview. And when third data is added, first data is replaced by second data, and second data is shown in listview. I have tried adding adapter.notifyDataSetChanged(), but still the same result.

Data is retrieved (and synchronized) from the Firebase Database to your app asynchronously. This means that your sectionDetailsArrayList may be modified at any time. When you modify the data, you need to tell the adapter about it, so that it can update the view.

private void fetchData(DataSnapshot dataSnapshot) {
    sectionDetailsArrayList.clear();

    SectionDetails sectionDetails = dataSnapshot.getValue(SectionDetails.class);
    sectionDetailsArrayList.add(sectionDetails);

    // tell the adapter that we changed its data
    adapter.notifyDataSetChanged();
}

This should update the view. But since you clear out the list for every child that gets added or changed, the app will only show the latest added/modified item.

Setting up a synchronized array in Firebase is somewhat involved, since you have to deal with all event types and with the fact that evens can happen in any order. For that reason we create the FirebaseUI library, which contains adapters from the Firebase Database to a ListView and RecyclerView.