Im struggling a little with my code. I have searched and tried many methods. My aim is remove the previous entry that Firebase has provided to my app, the firebase data is coming from an embedded device.I want to replace the value in my android app.
Firebase is working ok, The app will display the new value provided by firebase but will not delete the previous entry.
I still have plenty to do but want to fix the basics before moving on.
So basically the OnChildChanged will display new firebase entries, i just want the previous entry deleted from the Android Application when a new value comes in from Firebase.
I have looked into removeValue and setValue with no avail
public class MainActivity extends AppCompatActivity {
DatabaseReference fDatabase;
ListView listview;
ArrayList<String> list = new ArrayList<>();
ArrayAdapter <String> adapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview = (ListView) findViewById(R.id.listview);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, list);
listview.setAdapter(adapter);
fDatabase = FirebaseDatabase.getInstance().getReference();
fDatabase.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String value = dataSnapshot.getValue(String.class);
list.add(value);
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
String value = dataSnapshot.getValue(String.class);
list.remove(value);
adapter.notifyDataSetChanged();
list.add(value);
adapter.notifyDataSetChanged();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
String value = dataSnapshot.getValue(String.class);
list.remove(value);
adapter.notifyDataSetChanged();
list.add(value);
adapter.notifyDataSetChanged();
}
Looks like when you assign value it's getting the new entry, so when you call list.remove it isn't removing the old entry since it's actually trying to remove any instance of the new entry.
See if there's any way you can map the old entry to the new entry so the list knows what to remove since the content of value is different between old and new.
Related
This is my database and I wanna retrieve a data (which is underline in red color) from firebase to Listview .
This is the picture of my XML code
This is the my java code:
public class TimeTableActivity extends AppCompatActivity {
ListView table01;
DatabaseReference Trainline;
ArrayList<String> arrayList= new ArrayList<>();
ArrayAdapter<String> arrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_time_table);
Trainline= FirebaseDatabase.getInstance().getReference("Time_table");
table01 = findViewById(R.id.table01);
arrayAdapter = new ArrayAdapter<String>( TimeTableActivity.this, android.R.layout.simple_list_item_1);
table01.setAdapter(arrayAdapter);
Trainline.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
}
#Override
public void onChildChanged(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot snapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
In the onChildAdded you can:
Read the value from the snapshot
Add it to the list that the adapter is based on
Tell the adapter to refresh itself
In code:
arrayAdapter = new ArrayAdapter<String>(TimeTableActivity.this,
android.R.layout.simple_list_item_1, arrayList);
// 👆 Add this
Trainline.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
String value = snapshot.child("time_table").getValue(String.class); // 👈 1. Get the value
arrayList.add(value); // 👈 2. Add to the array
arrayAdapter.notifyDataSetChange(); // 👈 3. Tell the adapter to repaint.
}
...
When you read data in the firebase database, you should retrieve the entire data. So, there is no way to fetch only specific fields from the data returned on reading a path.
Because of that, if it's possible for your case, I would suggest you to add new data in firebase with the purpose of queries that only retrieve the information that you need.
For doing that, you can have a separate node that can be called something like TimeTable-SpecificList. Now, in this table, have user uid as your child keys, and each entry shall have only a timeTableSpecific field which you want to fetch.
Example:
replicaTimeTable :{
key1: {
timeTableSpecific: "Colombo-Gampaha ..."
},
key2: {
timeTableSpecific: "Colombo-Kandy ..."
},
key3: {...},
}
This solution to minimize download redundancy and optimize for speed then is the way to go!
Reference: Fetch particular fields from Firebase database
Is there any mistake in code because I am getting the only price in the listview and not the name can anyone help me out? I've tried so many methods to solve it but in last it let me post on StackOverflow to ask you people for the help, I am really stuck in it. I'll be really thankful to you for this help. Model class will also be provided if needed.
private ListView mlistView;
private ArrayList<String>list;
private ArrayAdapter<String> adapter;
private ArrayList<String>Pricelist;
private ArrayAdapter<String> Priceadapter;
private DatabaseReference ref;
private FirebaseDatabase database;
private FoodItemclass fooditem;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rice_after_login);
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
android.support.v7.app.ActionBar actionBar = getSupportActionBar();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
actionBar.setTitle("Rice");
fooditem = new FoodItemclass();
mlistView = (ListView)findViewById(R.id.listview);
database = FirebaseDatabase.getInstance();
ref = database.getReference("Rice");
list = new ArrayList<>();
Pricelist = new ArrayList<>();
adapter = new ArrayAdapter<String>(this,R.layout.list_item,R.id.ItemNameIds,list);
Priceadapter = new ArrayAdapter<String>(this,R.layout.list_item,R.id.ItemPriceId,Pricelist);
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
fooditem = dataSnapshot.getValue(FoodItemclass.class);
list.add(fooditem.getName());
Pricelist.add(String.valueOf(fooditem.getPrice()));
mlistView.setAdapter(adapter);
mlistView.setAdapter(Priceadapter);
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
you can only set one adapter to your list view so thats why you get the recent assign adapter result
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
fooditem = dataSnapshot.getValue(FoodItemclass.class);
list.add(fooditem.getName()+ " "+String.valueOf(fooditem.getPrice());
mlistView.setAdapter(adapter);
}
NOTE: the space between both name and price value is a separator
Recommend This is a bad approach to do so. you should use RecyclerView to show multiple values
The answer from faiizii has the gist of the problem: you can only have one adapter on a list view, so you should only call setAdapter once. Since onChildAdded will be called for each child, you shouldn't call setAdapter in there (nor in any of the other onChild... methods).
The solution is to move the calls to setAdapter out of the listener:
list = new ArrayList<>();
adapter = new ArrayAdapter<String>(this,R.layout.list_item,R.id.ItemNameIds,list);
mlistView.setAdapter(adapter);
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
fooditem = dataSnapshot.getValue(FoodItemclass.class);
list.add(fooditem.getName()+": "+fooditem.getPrice());
adapter.notifyDataSetChanged();
}
...
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
As you'll see we now call notifyDataSetChanged() inside onChildAdded. This lets the adapter know that its data has changed, which in turn then means that it refreshes the list view.
Working on an Android Project using Firebase.
The project is to let users check in and display all logs in a table view.
I have set up the firebase database as follows:
I can't get the entries to show in the table view?
I would like to show the following items per list item:
userCheckIn
username
userLocation
My code:
private ListView mListView;
private DatabaseReference mDatabse;
private ArrayList<String> arrayList = new ArrayList<>();
private ArrayAdapter<String> adapter;
String Date;
Calendar calendar;
SimpleDateFormat simpleDateFormat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account);
mListView = (ListView) findViewById(R.id.database_list_view);
calendar = Calendar.getInstance();
simpleDateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
Date = simpleDateFormat.format(calendar.getTime());
FirebaseUser currentFirebaseUser = FirebaseAuth.getInstance().getCurrentUser() ;
mDatabse = FirebaseDatabase.getInstance().getReference().child("CheckInOut").child(currentFirebaseUser.getUid()).child(Date).child("userCheckIn");
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, arrayList);
mListView.setAdapter(adapter);
mDatabse.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String string = dataSnapshot.getValue(String.class);
arrayList.add(string);
adapter.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) {
}
});
}
I would appreciate any support possible.
To solve this, move the declaration of your ArrayList and ArrayAdapter inside onChildAdded() method. You need also to set the adapter inside onChildAdded() method because this method has an asynchronous behaviour. This means that if you are trying to set the adapter outside onChildAdded() method it will always be empty because at that time you haven't got all the data from the database. So all operation must take place inside that method.
I recomand you also to use FirebaseUI. It will handle all the events for you. If want to read more about how you can get the data outside an asynchronous method, take a look at my answer from this post.
I have an android project where I retrieve data from firebase. everything is working fine but when I delete object in firebase console, it does not reflect back in the app.
Here is the link of the image:
So, suppose I delete david hafiz child node in firebase, it does not delete in the app. I have tried a lot but can't find the correct way. I am new to android programming and I hope somebody can help me. Thank You.
Update
mDatabase = FirebaseDatabase.getInstance();
mReference = mDatabase.getReference().child("Students").child("Marks");
mReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.d("value", "" + dataSnapshot);
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 view;
}
private void fetchData(DataSnapshot dataSnapshot) {
StudentData value = dataSnapshot.getValue(StudentData.class);
Log.v("StudentData Fragment", "" + dataSnapshot.getValue());
// Get an iterator.
Iterator<StudentData> ite = mMarksList.iterator();
while (ite.hasNext()) {
StudentData iteValue = ite.next();
if (iteValue.equals(value))
ite.remove();
}
mMarksList.add(value);
Collections.sort(mMarksList, new MarksComparator());
String title = mReference.getKey();
// specify an adapter
mAdapter = new MyAdapter(getContext(), mMarksList, title);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
}
There are four relevant methods in ``:
onChildAdded
onChildRemoved
onChildChanged
onChildMoved
You only implemented onChildAdded, which is called in two cases:
When you first attach the listener, onChildAdded is called for each existing child.
When a child is later added, onChildAdded is called for that child.
When you delete a node from the Firebase console, the onChildRemoved method is called. But since you left that method empty, your app doesn't do anything when you remove data from the console.
To make your app behave correctly, you'll need to implement onChildRemoved. Typically this involves finding the UI element matching the snapshot and removing it.
You can store keys in order to update or remove it e.g:
ArrayList<String> mKeys = new ArrayList<String>();
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String key = dataSnapshot.getKey();
mKeys.add(key);
adapter.notifyDataSetChanged();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
String key = dataSnapshot.getKey();
int index = mKeys.indexOf(key);
mMarksList.remove(/*index*/); // or data
adapter.notifyDataSetChanged();
}
You might be interested how to update too.
I have been searching for this but have not managed to find what I was looking for.
Here is an image of what I have in firebase.
I need to show it in the listview but also I need to show it dynamically. Such as if there are 30 links it should show 30 items in the listview and if there are 50 links here in Firebase the listview should have 50 items.
What would be the best possible way to do this?
Thanks
I have found a solution.
listview=(ListView)findViewById(R.id.listview);
final ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,list);
listview.setAdapter(adapter);
dref=FirebaseDatabase.getInstance().getReference();
dref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
list.add(dataSnapshot.getValue(String.class));
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
list.remove(dataSnapshot.getValue(String.class));
adapter.notifyDataSetChanged();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
This will show all the data of child in a listview