I am creating an android app in which I store in firebase and show a list with subitems in one activity and access that list in another activity by clicking a button. I have stored and showed the data in firebase and in my first activity, but I can't fetch that list in the other activity.
My code:-
Main Activity:-
public class MainActivity extends AppCompatActivity {
EditText getName, getNum;
Button btn,btnNext;
TextView textView;
ListView listView;
DatabaseReference fb;
List<Contact> contactList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getName = findViewById(R.id.ed1);
getNum = findViewById(R.id.ed2);
textView = findViewById(R.id.text);
btn = findViewById(R.id.btn);
btnNext = findViewById(R.id.btnNext);
listView = findViewById(R.id.listView);
fb = FirebaseDatabase.getInstance().getReference("Contacts");
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
finish();
}
});
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addContacts();
}
});
fb.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Contact contact = dataSnapshot.getValue(Contact.class);
contactList.add(contact);
listadapter list = new listadapter(MainActivity.this,contactList);
listView.setAdapter(list);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
notify();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
public void addContacts() {
String name = getName.getText().toString();
String num = getNum.getText().toString();
String id = fb.push().getKey();
Contact contact = new Contact(name,num);
fb.child(id).setValue(contact);
}
}
Contact getters class
public class Contact {
String contact;
String name;
public Contact() { }
public Contact(String name, String contact) {
this.name = name;
this.contact = contact;
}
public String getName() {
return name;
}
public String getContact() {
return contact;
}
}
custom adapter class
public class listadapter extends ArrayAdapter<Contact> {
private Activity context;
private List<Contact> contactList;
public listadapter(Activity context, List<Contact> contactList) {
super(context,R.layout.list,contactList);
this.context = context;
this.contactList = contactList;
}
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View listViewItem = inflater.inflate(R.layout.list, null, true);
TextView textViewName = listViewItem.findViewById(R.id.name);
TextView textViewContact = listViewItem.findViewById(R.id.num);
Contact contact = contactList.get(position);
textViewName.setText(contact.getName());
textViewContact.setText(contact.getContact());
return listViewItem;
}
}
Activity in which i'm trying to fetch
public class Main2Activity extends AppCompatActivity {
Button getSub;
List<Contact> list = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
getSub = findViewById(R.id.getSub);
getSub.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"Num : "+list.get(0).getContact(),Toast.LENGTH_LONG).show();
}
});
}
}
Solution:- I fetched the list directly from firebase and it works
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
call = findViewById(R.id.call);
db = FirebaseDatabase.getInstance().getReference("Trusted contacts");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
msgAll();
for(int i=0;i<ex.size();i++) {
getNum = "tel: "+ex.get(i).getmText2();
callAll(getNum);
}
}
}, 500);
}
#Override
protected void onStart() {
super.onStart();
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ExampleItem contact = dataSnapshot.getValue(ExampleItem.class);
ex.add(contact);
}
#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) {
}
});
}
In Main2Activity you have created the reference variable list as new ArrayList<>() but you have never added anything to it.
If you want to be able to access the data, you'll need to either pass it from one Actvity to another, or store a reference to it in a static variable that you can access from both classes.
Related
I want to get data from a Firebase database in a list view. When I open the page, it appears as follows:
When I go back and open it again, it now appears like this:
The database contains the following data:
My two problems are:
It takes a lot of time to retrieve the data
More data is retrieved than expected - it is repeated in the listview.
My code:
public class CustomAdapter extends BaseAdapter{
Context c;
ArrayList<Doctor> doctors;
public CustomAdapter(Context c, ArrayList<Doctor> doctors) {
this.c = c;
this.doctors = doctors;
}
#Override
public int getCount() {
return doctors.size();
}
#Override
public Object getItem(int position) {
return doctors.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.model,parent,false);
}
TextView nameTxt= (TextView) convertView.findViewById(R.id.nameTxt);
TextView propTxt= (TextView) convertView.findViewById(R.id.propellantTxt);
TextView descTxt= (TextView) convertView.findViewById(R.id.descTxt);
final Doctor s= (Doctor) this.getItem(position);
nameTxt.setText(s.getDoctorName());
propTxt.setText(s.getSpecialist());
descTxt.setText(s.getAdress());
//ONITECLICK
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(c,s.getDoctorName(),Toast.LENGTH_SHORT).show();
}
});
return convertView;
}
and this for model class
public class Doctor {
String doctorName,specialist,adress;
public Doctor() {
}
public String getDoctorName() {
return doctorName;
}
public String getSpecialist() {
return specialist;
}
public String getAdress() {
return adress;
}
The Activity:
public class DoctorsActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper helper;
CustomAdapter adapter;
ListView lv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_doctors);
lv = (ListView) findViewById(R.id.lv);
db = FirebaseDatabase.getInstance().getReference().child("Doctor");
helper = new FirebaseHelper(db);
adapter = new CustomAdapter(this, helper.retrieve());
lv.setAdapter(adapter);
}
Firebase Helper:
public class FirebaseHelper {
DatabaseReference db;
Boolean saved;
ArrayList<Doctor> doctors = new ArrayList<>();
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
//IMPLEMENT FETCH DATA AND FILL ARRAYLIST
private void fetchData(DataSnapshot dataSnapshot) {
doctors.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Doctor doctor = dataSnapshot.getValue(Doctor.class);
doctors.add(doctor);
}
}
//RETRIEVE
public ArrayList<Doctor> 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 doctors;
}
I am making an android app ,which is get order from customers,but i faced a problem . I am trying to Retrieve Data from Firebase and display in a list view. I can get the data back from Firebase but when it displays in the listview it just displays one data in many times. I want to be displayed on one line for each record. Can anyone see where i am going wrong??
Database Image
ListView Image
OrderHistory
public class OrderHistory
{
String ammount,photoId,trxId,name,copy,photoSize,date;
public OrderHistory(String name,String photoId,String trxId,String copy,String photoSize,String ammount,String date)
{
this.name = name;
this.ammount = ammount;
this.photoId = photoId;
this.copy = copy;
this.photoSize = photoSize;
this.trxId = trxId;
this.date = date;
}
public String getAmmount() {
return ammount;
}
public void setAmmount(String ammount) {
this.ammount = ammount;
}
public String getPhotoId() {
return photoId;
}
public void setPhotoId(String photoId) {
this.photoId = photoId;
}
public String getTrxId() {
return trxId;
}
public void setTrxId(String trxId) {
this.trxId = trxId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCopy() {
return copy;
}
public void setCopy(String copy) {
this.copy = copy;
}
public String getPhotoSize() {
return photoSize;
}
public void setPhotoSize(String photoSize) {
this.photoSize = photoSize;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
OrderHistoryAdapter
public class OrderHistoryAdapter extends BaseAdapter {
private List<OrderHistory> orderHistories;
Context context;
public OrderHistoryAdapter(Context context, List<OrderHistory> myOrderInformations) {
this.context = context;
this.orderHistories = myOrderInformations;
}
#Override
public int getCount() {
return orderHistories.size();
}
#Override
public Object getItem(int position) {
return orderHistories.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.show_my_order_history, parent, false);
final TextView txtName, txtdate, txtPhotoId, trxId,txtAmount,txtPhotoSize,txtCopy;
txtName = (TextView)view.findViewById(R.id.txtName);
txtdate = (TextView)view.findViewById(R.id.txtDate);
txtPhotoId = (TextView)view.findViewById(R.id.txtPhotoId);
trxId = (TextView)view.findViewById(R.id.txtTrx);
txtAmount = (TextView)view.findViewById(R.id.txtAmount);
txtPhotoSize = (TextView)view.findViewById(R.id.txtSize);
txtCopy = (TextView)view.findViewById(R.id.txtCopy);
txtName.setText(orderHistories.get(position).getName());
txtdate.setText(orderHistories.get(position).getDate());
txtPhotoId.setText(orderHistories.get(position).getPhotoId());
trxId.setText(orderHistories.get(position).getTrxId());
txtAmount.setText(orderHistories.get(position).getAmmount());
txtCopy.setText(orderHistories.get(position).getCopy());
txtPhotoSize.setText(orderHistories.get(position).getPhotoSize());
return view;
}
}
OrderHistoryList
public class OrderHistoryList extends AppCompatActivity
{
private DatabaseReference databaseReference;
private List<OrderHistory> orderHistories;
private static String phoneNumber;
private ListView listView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_my_order);
Firebase.setAndroidContext(this);
listView = (ListView)findViewById(R.id.listView);
getAllOrderFromFirebase();
}
private void getAllOrderFromFirebase()
{
orderHistories = new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("order");
String phone = getIntent().getExtras().getString("phone");
databaseReference.orderByChild("phone").equalTo(phone).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String amount, photoId, trxId, name, copy, photoSize, date;
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
name = snapshot.child("name").getValue(String.class);
photoId = snapshot.child("photoId").getValue(String.class);
amount = snapshot.child("totalAmount").getValue(String.class);
trxId = snapshot.child("trxId").getValue(String.class);
photoSize = snapshot.child("photoSize").getValue(String.class);
date = snapshot.child("date").getValue(String.class);
copy = snapshot.child("totalCopy").getValue(String.class);
orderHistories.add(new OrderHistory(name, photoId, trxId, copy, photoSize, amount, date));
}
OrderHistoryAdapter adapter;
adapter = new OrderHistoryAdapter(OrderHistoryList.this, orderHistories);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
}
#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) {
}
});
}
}
I guess your problem is by the way you refer to your data so instead of this
databaseReference = FirebaseDatabase.getInstance().getReference("order");
use this
databaseReference = FirebaseDatabase.getInstance().getReference().child("order");
and you didn't use a query object to query your database reference
so now you don't query directly from databaseReference like the way you did it
instead you do this:
Query query=databaseReference.orderByChild("phone").equalTo(phone);
once you have a query that fits you now add on child listener and continue the rest of your code:
query.addChildEventListener(new ChildEventListener() {
//the rest of your code goes here(on child added/changed/......)
)};
I am developing application which keeps user expenses, I wrote CustomAdapter
public class CustomAdapter extends BaseAdapter{
Context c;
ArrayList<Income> incomes;
public CustomAdapter(){}
public CustomAdapter(Context c,ArrayList<Income> incomes){
this.incomes=incomes;
this.c=c;
}
#Override
public int getCount() {
return incomes.size();
}
#Override
public Object getItem(int position) {
return incomes.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
convertView= LayoutInflater.from(c).inflate(R.layout.model,parent,false);
}
TextView nameTxt= (TextView) convertView.findViewById(R.id.nameTxt);
TextView propTxt= (TextView) convertView.findViewById(R.id.aciklama);
TextView descTxt= (TextView) convertView.findViewById(R.id.descTxt);
Income s= (Income) this.getItem(position);
nameTxt.setText(s.getName());
propTxt.setText(s.getType());
descTxt.setText((String.valueOf(s.getMiktar())));
return convertView;
}
and implemented on the activity
public class ExpenseActivity extends Activity{
DatabaseReference db;
FloatingActionButton fab;
ExpenseAdapter adapter;
ListView lv;
Boolean saved;
EditText nameEditTxt, propTxt, descTxt;
ArrayList<Expense> expenselist = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.expense_content);
//Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar);
// setSupportActionBar(toolbar);
lv = (ListView) findViewById(R.id.listview);
db = FirebaseDatabase.getInstance().getReference();
//isa
adapter = new ExpenseAdapter(ExpenseActivity.this, getExpenses());
lv.setAdapter(adapter);
adapter.notifyDataSetChanged();
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
displayInput();
}
});
}
public Boolean save(Expense expense){
if(expense==null){
saved=false;
}else{
try{
db.child("Expense").push().setValue(expense);
saved=true;
}catch (Exception ex){
ex.printStackTrace();;
saved=false;
}
}
return saved;
}
public void fetchData(DataSnapshot dataSnapshot)
{
expenselist.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Expense expense=ds.getValue(Expense.class);
expenselist.add(expense);
adapter.notifyDataSetChanged();
}
}
public ArrayList<Expense> getExpenses(){
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 expenselist;
}
private void displayInput() {
final Dialog d=new Dialog(this);
d.setTitle("Gelir Girin");
d.setContentView(R.layout.expense_layout);
nameEditTxt = (EditText) d.findViewById(R.id.name);
propTxt = (EditText) d.findViewById(R.id.kategori);
descTxt = (EditText) d.findViewById(R.id.miktar);
Button saveBtn = (Button) d.findViewById(R.id.saveBtn);
saveBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String name = nameEditTxt.getText().toString();
String type = propTxt.getText().toString();
String amount= String.valueOf(descTxt.getText().toString());
Expense expense=new Expense(name,type,amount);
if (name != null && name.length() > 0) {
//THEN SAVE
if (save(expense)) {
//IF SAVED CLEAR EDITXT
d.cancel();
nameEditTxt.setText("");
propTxt.setText("");
descTxt.setText("");
}
} else {
Toast.makeText(ExpenseActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
}
}
});
d.show();
}
but even I have some data saved in firebase it returns null and passes null to fields(textview) at first but when I add new item it show existing data in the Firebase. One of my friend said that I am calling data asnychronously but I didn't understand it.I want to data be shown directly whenever activity is opened. Any help is appreciated,Thanks
When I open activity:
After I add new data:
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
fetchdata();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
This will fetch appropriate data
Your problem is that your are initializing your adapter before fetching the data from the db.
adapter = new ExpenseAdapter(ExpenseActivity.this, getExpenses());
The getExpenses() method is performing an asynchronous operation
Try passing instead the list directly and call the getExpenses method as well
adapter = new ExpenseAdapter(ExpenseActivity.this, expenselist);
getExpenses()
Then when the notifyDatasetChanged is called in the fetchData method it will update the list.
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().
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.