Data from Firebase not automatically loading Android Studio [duplicate] - android

This question already has answers here:
Recylerview not automatically loading data from firebase Android Studio
(4 answers)
Closed 6 years ago.
I have tried adapter.notifyDataSetChanged(); and all the other solutions I could find online but my data from firebase does not automatically load and I need to click a edit text box to load the data. Please can someone guide me on how I can solve this. Thanks.
My Adapter is looks like:
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
Context c;
ArrayList<Spacecraft> spacecrafts;
public MyAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
this.c = c;
this.spacecrafts = spacecrafts;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v=LayoutInflater.from(c).inflate(R.layout.model,parent,false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final Spacecraft s=spacecrafts.get(position);
holder.nameTxt.setText(s.getName());
holder.propTxt.setText(s.getPropellant());
holder.descTxt.setText(s.getDescription());
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(int pos) {
//OPEN DETAI ACTIVITY
openDetailActivity(s.getName(),s.getDescription(),s.getPropellant());
}
});
}
#Override
public int getItemCount() {
return spacecrafts.size();
}
//OPEN DETAIL ACTIVITY
private void openDetailActivity(String...details)
{
Intent i=new Intent(c,DetailActivity.class);
i.putExtra("NAME_KEY",details[0]);
i.putExtra("DESC_KEY",details[1]);
i.putExtra("PROP_KEY",details[2]);
c.startActivity(i);
}
}
This is how I am reading data from firebase
public class FirebaseHelper {
DatabaseReference db;
Boolean saved=null;
ArrayList<Spacecraft> spacecrafts=new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//WRITE IF NOT NULL
public Boolean save(Spacecraft spacecraft)
{
if(spacecraft==null)
{
saved=false;
}else
{
try
{
db.child("Spacecraft").push().setValue(spacecraft);
saved=true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved=false;
}
}
return saved;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST
private void fetchData(DataSnapshot dataSnapshot)
{
spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
}
}
//READ THEN RETURN ARRAYLIST
public ArrayList<Spacecraft> 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 spacecrafts;
}
}
In my mainactivity I am setting the adpater like this:
db= FirebaseDatabase.getInstance().getReference();
FirebaseHelper = new FirebaseHelper(db);
adapter = new MyAdapter(getActivity(), FirebaseHelper.retrieve());
adapter .notifyDataSetChanged();
recycler.setAdapter(adapter );
adapter .notifyDataSetChanged();
I have tried placing the adapter.notifyDataSetChanged(); in many places and classes but not luck. Any help will be nice as this is really pushing me back and has been bugging me for a while now. Thanks and let me know if I can provide any more code.

Reading data in Firebase is asynchronous. So technically, you're returning spacecrafts while it is still empty (because the data reading is still happening asynchronously). I suggest you take a look at FirebaseUI for Android as it can easily help you synchronize your data with your RecyclerView.

Related

I'm trying to get Item Count from custom Adapter for a chat application but it always returns zero how to resolve this?

I'm making a chat application with RecyclerView and List class to store messages from Firebase Database and want to scroll at the bottom of the recylcerView when Chat Activity is opened but error is.....Adapter always returns zero while calling adapter.getItemcount() method . All messages are being displayed with no problem.
Custom Adapter java file
public class ChatCustomAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private FirebaseUser mUser;
private String currentUser;
private List<ChatModel> msgList;
//Constructor
public ChatCustomAdapter(List<ChatModel> msgList) {
this.msgList = msgList;
FirebaseAuth mAuth = FirebaseAuth.getInstance();
mUser = mAuth.getCurrentUser();
currentUser = mUser.getUid();
}
#Override
public int getItemCount() {
return msgList.size();
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
if(viewType==0){
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_single__user_item_layout,parent,false);
return new SelfViewHolder(v);
}else if(viewType==1){
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_single_other_user_item_layout,parent,false);
return new OtherViewHolder(v);
}else{
return null;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int layout = holder.getItemViewType();
ChatModel model = msgList.get(position);
String msg = model.getMsg();
if(layout==0){
SelfViewHolder sHolder = (SelfViewHolder)holder;
sHolder.setSelfMsgItems(msg);
}else if(layout==1){
OtherViewHolder oHolder = (OtherViewHolder)holder;
oHolder.setOtherMsgItems(msg);
}
}
#Override
public int getItemViewType(int position) {
super.getItemViewType(position);
int layout;
ChatModel model = msgList.get(position);
String from = model.getFrom();
if(from.equals(currentUser)){
layout=0;
}else{
layout=1;
}
return layout;
}
class SelfViewHolder extends RecyclerView.ViewHolder{
TextView msgtxt,timetxt;
SelfViewHolder(View itemView) {
super(itemView);
msgtxt = itemView.findViewById(R.id.chat_sinhle_user_item_textview);
timetxt = itemView.findViewById(R.id.chat_sinhle_user_item_timeview);
}
void setSelfMsgItems(String data){
msgtxt.setText(data);
}
}
class OtherViewHolder extends RecyclerView.ViewHolder{
TextView msgtxt,timetxt;
public OtherViewHolder(View itemView) {
super(itemView);
msgtxt = itemView.findViewById(R.id.chat_other_user_item_textview);
timetxt = itemView.findViewById(R.id.chat_other_user_item_timeview);
}
public void setOtherMsgItems(String data){
msgtxt.setText(data);
}
}
}
Chat Activity java file
protected void onStart() {
super.onStart();
//region RETREIVING MESSAGES FROM SERVER
msgQ = mDatabase.child("messages").child(current_user).child(otherusername).orderByChild("time");
msgQ.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ChatModel model = dataSnapshot.getValue(ChatModel.class);
mLsit.add(msgposition++, model);
mAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//endregion
recyclerView.scrollToPosition(mAdapter.getItemCount()-1);
}
I think getItemCount() returns zero because you call this method outside of ChildEventListener. So you retrieve itemcount when there are no elements in mLsit yet.
The fastest and a little bit dirty solution here is to put scrollToPosition in onChildAdded method. Also, I would modify code this way
protected void onStart() {
super.onStart();
//region RETREIVING MESSAGES FROM SERVER
msgQ = mDatabase.child("messages").child(current_user).child(otherusername).orderByChild("time");
msgQ.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ChatModel model = dataSnapshot.getValue(ChatModel.class);
mLsit.add(msgposition, model);
mAdapter.notifyItemInserted(msgposition)
recyclerView.scrollToPosition(msgposition);
msgposition++;
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//endregion
}

Firebase not writing to expected child, updating it on next child in Android

Tried answers found on the internet, actually there is no change to the code as it seem correct but can't find where is the error.
My Input Parameters:
JSON RETURNED:
(I expected a "clocation" child and value but it won't even write that to the tree. Plus, the value of clocation is written to cbudget)
Project Class:
public class Project {
String ctitle, cdetail, clocation, cbudget;
public Project() {
}
public String getCtitle() {
return ctitle;
}
public void setCtitle(String ctitle) {
this.ctitle = ctitle;
}
public String getCdetail() {
return cdetail;
}
public void setCdetail(String cdetail) {
this.cdetail = cdetail;
}
public String getClocation() {
return clocation;
}
public void setClocation(String clocation) {
this.clocation = clocation;
}
public String getCbudget() {
return cbudget;
}
public void setCbudget(String cbudget) {
this.cbudget = cbudget;
}
MyViewHolder
public MyViewHolder(View itemView) {
super(itemView);
titleTxt = (TextView) itemView.findViewById(R.id.titleTxt);
detailTxt = (TextView) itemView.findViewById(R.id.detailTxt);
locationTxt = (TextView) itemView.findViewById(R.id.locationTxt);
budgetTxt = (TextView) itemView.findViewById(R.id.budgetTxt);
itemView.setOnClickListener(this);
}
MyAdapter
public MyAdapter(Context c, ArrayList<Project> projects) {
this.c = c;
this.projects = projects;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(c).inflate(R.layout.model,parent,false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final Project s = projects.get(position);
holder.titleTxt.setText(s.getCtitle());
holder.detailTxt.setText(s.getCdetail());
holder.locationTxt.setText(s.getClocation());
holder.budgetTxt.setText(s.getCbudget());
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(int pos) {
//OPEN DETAIL ACTIVITY
openDetailActivity(s.getCtitle(),s.getCdetail(),s.getClocation(),s.getCbudget());
}
});
}
#Override
public int getItemCount() {
return projects.size();
}
//OPEN DETAIL ACTIVITY
private void openDetailActivity(String...details)
{
Intent i=new Intent(c,DetailActivity.class);
i.putExtra("TITLE_KEY",details[0]);
i.putExtra("DETAIL_KEY",details[1]);
i.putExtra("LOCATION_KEY",details[2]);
i.putExtra("BUDGET_KEY",details[3]);
c.startActivity(i);
}
FirebaseHelper
public class FirebaseHelper {
DatabaseReference db;
Boolean saved = null;
ArrayList<Project> projects=new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//WRITE IF NOT NULL
public Boolean save(Project project)
{
if(project==null)
{
saved=false;
}
else
{
try
{
db.child("Project").push().setValue(project);
saved=true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved=false;
}
}
return saved;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST
private void fetchData(DataSnapshot dataSnapshot)
{
projects.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Project project = ds.getValue(Project.class);
projects.add(project);
}
}
//READ THEN RETURN ARRAYLIST
public ArrayList<Project> 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 projects;
}
}
Receive and Bind Data:
//RECEIVE DATA
String title = i.getExtras().getString("TITLE_KEY");
String detail = i.getExtras().getString("DETAIL_KEY");
String location = i.getExtras().getString("LOCATION_KEY");
String budget = i.getExtras().getString("BUDGET_KEY");
//BIND DATA
titleTxt.setText(title);
detailTxt.setText(detail);
locationTxt.setText(location);
budgetTxt.setText(budget);
The problem in your code is that you are declaring the ArrayList<Project> projects=new ArrayList<>(); outside onChildAdded() and onChildChanged() methods. This means that your projects ArrayList is null, due the asyncronious behaviour of those methods, which are called before even you add those objects to the list.
To solve this, you need to declare that ArrayList inside fetchData() method right before that for loop.
This change will solve your problem.

Recylerview not automatically loading data from firebase Android Studio

I have tried everything but my data from firebase is not getting loaded automatically when I open the app and I have to click a edittext to load the data.
I have tried
adapter.Update(data);
recycler.invalidate();
notifyDataSetChanged();
adapter.notifyDataSetChanged();
Please can someone help me out.
EDITED:
I am saving to firebase like this:
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//WRITE IF NOT NULL
public Boolean save(Spacecraft spacecraft)
{
if(spacecraft==null)
{
saved=false;
}else
{
try
{
db.child("Spacecraft").push().setValue(spacecraft);
saved=true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved=false;
}
}
return saved;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST
private void fetchData(DataSnapshot dataSnapshot)
{
spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
}
}
//READ THEN RETURN ARRAYLIST
public ArrayList<Spacecraft> 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);
}
});
return spacecrafts;
}
}
My viewholder class
public MyViewHolder(View itemView) {
super(itemView);
nameTxt= (TextView) itemView.findViewById(R.id.nameTxt);
propTxt= (TextView) itemView.findViewById(R.id.propellantTxt);
descTxt= (TextView) itemView.findViewById(R.id.descTxt);
itemView.setOnClickListener(this);
}
public void setItemClickListener(ItemClickListener itemClickListener)
{
this.itemClickListener=itemClickListener;
}
#Override
public void onClick(View view) {
this.itemClickListener.onItemClick(this.getLayoutPosition());
}
My adapter class
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
Context c;
ArrayList<Spacecraft> spacecrafts;
public MyAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
this.c = c;
this.spacecrafts = spacecrafts;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v=LayoutInflater.from(c).inflate(R.layout.model,parent,false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final Spacecraft s=spacecrafts.get(position);
holder.nameTxt.setText(s.getName());
holder.propTxt.setText(s.getPropellant());
holder.descTxt.setText(s.getDescription());
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(int pos) {
//OPEN DETAI ACTIVITY
openDetailActivity(s.getName(),s.getDescription(),s.getPropellant());
}
});
}
#Override
public int getItemCount() {
return spacecrafts.size();
}
//OPEN DETAIL ACTIVITY
private void openDetailActivity(String...details)
{
Intent i=new Intent(c,DetailActivity.class);
i.putExtra("NAME_KEY",details[0]);
i.putExtra("DESC_KEY",details[1]);
i.putExtra("PROP_KEY",details[2]);
c.startActivity(i);
}
in my mainactivity in onCreate I am calling the data like this
recycler = (RecyclerView) rootView.findViewById(R.id.recycler);
recycler.setLayoutManager(new LinearLayoutManager(getActivity()));
database = FirebaseDatabase.getInstance().getReference();
spacecraft = new ArrayList<>();
firebasehelper = new FirebaseHelper(database);
adapter = new JAdapter(getActivity(), firebasehelper.retrieve());
recycler.setAdapter(adapter);
The problem is with the retrieve method: it's adding a ChildEventListener that executes asynchronously (meaning it doesn't block until the children data are fetched) and then it immediately returns the spacecrafts list which is still not yet filled by the asynchronous listener code.
You should refresh the RecyclerView adapter in the actual code that fetches data, i.e. in the fetchData method, e.g.:
private void fetchData(DataSnapshot dataSnapshot)
{
spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
}
adapter.spacecrafts = spacecrafts; // update the list in the adapter
adapter.notifyDataSetChanged(); // refresh
}
In this case, the retrieve method can have a void return type as it is pointless to return the list from it.
Use FirebaseRecyclerAdapter for load the data from Firebase.
modify the helper constructer to be like this:
public FirebaseHelper(Context c, DatabaseReference db, ListView lv) {
this.c = c;
this.db = db;
this.lv = lv;
}
then add this to the fetchData method after the for loop:
if (spacecrafts.size() > 0)
{
adapter = new CustomAdapter(c, spacecrafts);
lv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
then in the main activity modify it like this:
helper = new FirebaseHelper(this, db, lv);
//ADAPTER
//adapter = new CustomAdapter(this, helper.retrieve());
//lv.setAdapter(adapter);
helper.retrieve();
this should work for you.
Check if you are setting up adapter in onCreate() method or not, if you are calling it in onStart() then it will not load data automatically. Set Adapter in onCreate() method.

Android - Update and delete data in Firebase database

I'm trying to update and delete data in Firebase database.
SectionDetails model
public class SectionDetails {
private String sectionCode;
private String sectionSeats;
private String sectionKey;
public SectionDetails() {
}
public SectionDetails(String sectionCode, String sectionSeats) {
this.sectionCode = sectionCode;
this.sectionSeats = sectionSeats;
}
#Exclude
public String getSectionKey() {
return sectionKey;
}
public String getSectionCode() {
return sectionCode;
}
public String getSectionSeats() {
return sectionSeats;
}
}
FirebaseHelper class
public class FirebaseHelper {
DatabaseReference db;
ArrayList<SectionDetails> sectionDetailsArrayList = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
private void fetchData(DataSnapshot dataSnapshot) {
SectionDetails sectionDetails = dataSnapshot.getValue(SectionDetails.class);
sectionDetailsArrayList.add(sectionDetails);
adapter.notifyDataSetChanged();
}
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) {
adapter.notifyDataSetChanged();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return sectionDetailsArrayList;
}
}
CustomAdapter class
public class CustomAdapter extends BaseAdapter {
DatabaseReference updateRef;
String key;
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) {
final SectionDetails sd = (SectionDetails) this.getItem(position);
updateRef = FirebaseDatabase.getInstance().getReference().child(Constants.FIREBASE_COURSES).child("sections");
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Dialog d = new Dialog(CustomAdapter.this);
d.setContentView(R.layout.section_custom_dialog);
Button btnUpdate = (Button) d.findViewById(R.id.btnUpdate);
Button btnDelete = (Button) d.findViewById(R.id.btnDelete);
btnUpdate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String code = "1B";
final String seats = "20";
updateRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
SectionDetails updateSD = snapshot.getValue(SectionDetails.class);
if (sd.getSectionCode().equals(updateSD.getSectionCode())) {
key = snapshot.getKey().toString();
}
}
SectionDetails newSD = new SectionDetails(code, seats);
updateRef.child(key).setValue(newSD);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
btnDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
SectionDetails deleteSD = snapshot.getValue(SectionDetails.class);
if (sd.getSectionCode().equals(deleteSD.getSectionCode())) {
updateSectionRef.child(snapshot.getKey().toString()).removeValue();
break;
}
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
d.show();
}
});
return convertView;
}
}
MainActivity class
public class MainActivity extends AppCompatActivity {
DatabaseReference mRef;
FirebaseHelper helper;
CustomAdapter adapter;
ListView lvSectionsListOne;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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);
}
}
The data is deleted from database as expected, but the data that gets deleted remains inside the listview. I added adapter.notifyDataSetChanged() but still the listview is not updating.
The data is also updated as expected, but when update button is clicked, the data is updated infinitely. I can see the listview as well as the database keep on appending the data, and can only be stopped by closing the app.
I have tried to move SectionDetails newSD = new SectionDetails(code, seats) and updateRef.child(key).setValue(newSD) to outside for loop but the data doesn't get updated because the key is not passed to the path outside the for loop.
I haven't thoroughly looked at all the code you posted and may not understand your processing completely. There are two things that might be causing some of the problems you described.
In FirebaseHelper, method onChildChanged() calls fetchData(), which adds the changed section details to the array list. Shouldn't you be updating the existing section details instead of adding them again? Also, in onChildRemoved(), the section details are not removed from the array list. Don't they need to be removed?
In CustomAdapter the click listeners for your buttons add anonymous ValueEventListeners. Because they are anonymous, you have no way of removing them when they are no longer needed. ValueEventListeners added with addValueEventListener() remain active until removed. If your goal is to get the data once, use addListenerForSingleValueEvent().

Android - Display data in ListView from Firebase database

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.

Categories

Resources