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.
Related
I am building an android app in which when the user create its account as a technician his name id display in a listview in which other users which don't have firebase outh.the problem is that I am unable to show data of technicians in the listview.
This is my firebase database
This is my code that return 0 items or blank listview. I tried several things, but unable to display the information of technicians. Anyone please help me with this I am new in firebase.
public class Technician extends Activity {
ListView listView;
ArrayList<String> tecnames = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_technician);
ImageButton Back_Btn = (ImageButton) findViewById(R.id.back);
Back_Btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(Technician.this, Technician_main.class);
startActivity(i);
finish();
}
});
listView = (ListView) findViewById(R.id.list_item);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Intent intent = new Intent(Technician.this, Book_Now.class);
startActivity(intent);
finish();
}
});
Technician.CostumAdapter costumAdapter = new Technician.CostumAdapter();
listView.setAdapter(costumAdapter);
GetItems();
}
private class CostumAdapter extends BaseAdapter {
#Override
public int getCount() {
return tecnames.size();
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = getLayoutInflater().inflate(R.layout.cuctom_listview, null);
TextView txt_one = (TextView) view.findViewById(R.id.skill_txt);
txt_one.setText(tecnames.get(i));
return view;
}
}
private void GetItems() {
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("user");
final Query itemsQuery = ref.orderByChild("name");
itemsQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) {
Pojo item = singleSnapshot.getValue(Pojo.class);
tecnames.add(String.valueOf(item));
Log.e(TAG,"value of name"+itemsQuery);
}
}else {
Toast.makeText(getApplicationContext(),"error",Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Log.e(TAG, "Returning " + tecnames.size() + " items");
}
}
instead of this:
Technician.CostumAdapter costumAdapter = new Technician.CostumAdapter();
Write this:
Technician.CostumAdapter costumAdapter = new Technician.CostumAdapter(getApplicationContext(),tecnames);
Then add this constructor inside of the class:
private ArrayList<String> datas;
Context mContext;
public CustomAdapter(Context context, ArrayList<String> datas) {
super(context, R.layout.row_item, datas);
this.mContext=context;
this.datas = datas;
}
change addListenerforSingleValueEvent to addValueEventListener
Ok, there are few things that you need to fix:
1.Your array list tecnames should be of your POJO class
ArrayList<POJO> tecnames = new ArrayList<>();
Now change tecnames.add(String.valueOf(item)); to tecnames.add(item);
2.As #Peter Haddad suggested, you need to give this list to your adapter as a dataset.
3.Firebase DB listeners are asynchronous so you need to notify your adapter after you get data in your dataset(list). Add the following code inside onDataChange after your foreach loop:
costumAdapter.notifyDataSetChanged();
You can refer to this link for the 3rd point.
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.
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.
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.