Updating ArrayList when the data is changed in Firebase - java

I am using an ArrayList (in Android) that contains the values from the Firebase database. Whenever the data is added or deleted, I want the list to be updated. To do this I used ChildEventListener but I am unsure whether this is a proper way of doing it as I face errors sometimes while deleting the elements from the list. There's no problem at all when adding elements to the list. But When I try to delete the last element from the list, I get ArrayIndexOutOfBounds Exception or some other Exception like length=12 index=-1. So, please go through my code and suggest a better way to delete elements:
public class Join extends AppCompatActivity {
DatabaseReference databaseReference;
ListView listView;
public static ArrayList<String> keysArrayList;
//To store the keys from Firebase
public static ArrayList<String> namesArrayList;
//To store the value or name associated with the key
ArrayAdapter<String> arrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join);
databaseReference = FirebaseDatabase.getInstance().getReference().child(“Queue Codes”);
listView = (ListView) findViewById(R.id.listViewForMember);
keysArrayList = new ArrayList<>();
namesArrayList = new ArrayList<>();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>
(this,android.R.layout.activity_list_item,namesArrayList);
listView.setAdapter(arrayAdapter);
/* Here I am trying to store Random keys from Firebase in
‘keysArrayList’ and their values in ‘namesArrayList’ and update these
lists whenever a value is added or removed from the database*/
databaseReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String addedKey = dataSnapshot.getKey();
String addedName = dataSnapshot.getValue(String.class);
keysArrayList.add(addedKey);
namesArrayList.add(addedName);
arrayAdapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
String removedKey = dataSnapshot.getKey();
int index = keysArrayList.indexOf(removedKey);
namesArrayList.remove(index);
keysArrayList.remove(removedKey);
arrayAdapter.notifyDataSetChanged();
/* Here I tried to remove the name from the ‘namesArrayList’ by
using the index of removed value from ‘keysArrayList’ as both
the lists would be of the same size anytime. I can simply
delete the name from the ‘namesArrayList’ by reading the
removed value from firebase but gets difficult when I use
Custom Array Lists which may contain many other objects. So, I
decided to delete the name using key index. */
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}

In order to solve this problem, you need to remove that particular element first from the adapter. If you want not to worry about adding or removing elements, I recommend you see my answer from this post, in which I have explained how you can get data from the Firebase Realtime database and display it in a ListView using an ArrayAdapter.

Related

How can I retrieve second data from array list

I can only retrieve first data "9780071792745" from my database. The app crashed when I tried to retrieve data from b. Here is my code
public class wish_list extends AppCompatActivity {
TextView display;
//private String wishlist;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wish_list);
display=(TextView)findViewById(R.id.tvDisplay);
//start here
DatabaseReference myRef = FirebaseDatabase.getInstance().getReference().child("Users")
.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child("Wishlist");
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
List<String> wishlist_item = new ArrayList<String>();
for (DataSnapshot postSnapshot: snapshot.getChildren()) {
wishlist_item.add(postSnapshot.getValue().toString());//got all wish list item from database
String a = wishlist_item.get(0);
String b = wishlist_item.get(1);
display.setText("Hi" + a);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
I can only retrieve from String a = wishlist_item.get(0) and cannot retrieve from String b = wishlist_item.get(1);
How can I retrieve?
Here is my data structure from my firebase database:
I can also tried to retrieve like this display.setText("Hi" + wishlist_item); and it worked but cannot retrieve from display.setText("Hi" + b);
error is :
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at java.util.ArrayList.get(ArrayList.java:437)
You are trying to retrive data from index 1 while that index is not created yet. When you enter the for loop, the for loop is getting the first item from the snapshot and adding it to the wishlist_item arraylist. What you need to do is this:
List<String> wishlist_item = new ArrayList<String>();
for (DataSnapshot postSnapshot: snapshot.getChildren()) {
wishlist_item.add(postSnapshot.getValue().toString());//got all wish list item from database
}
String a = wishlist_item.get(0);
String b = wishlist_item.get(1);
display.setText("Hi" + a);
This will work. Because you let your foreach loop to finish. This line:
wishlist_item.add(postSnapshot.getValue().toString());//got all wish list item from database
won't put all items from a snapshot, it will add one item at the time, the one that foreach loop is using right now. You first need to understand how for and foreach loops work: https://www.geeksforgeeks.org/for-each-loop-in-java/

How to retrieve a Boolean value from Firebase to a TextView?

I'm making a shopping app and User has to subscribe to the 'Fast-delivery' option if he needs to order it faster. When the User puts a tick to the 'Fast-delivery' Checkbox, the boolean value is being uploaded to the Firebase realtime database -->
database
And I want to see if the User has subscribed to the 'Fast-delivery' option from the Admin Panel. I retrieve all the order information to a RecyclerView in the Admin Panel. I want to set a TextView as "Fast Delivery : On/Off" when the Admin views the order details from the Admin Panel.
This is what I have tried:
#Override
protected void onStart()
{
super.onStart();
ordersRef = FirebaseDatabase.getInstance().getReference().child("Orders");
FirebaseRecyclerOptions<AdminOrders> options =
new FirebaseRecyclerOptions.Builder<AdminOrders>()
.setQuery(ordersRef, AdminOrders.class)
.build();
FirebaseRecyclerAdapter<AdminOrders, AdminOrdersViewHolder> adapter =
new FirebaseRecyclerAdapter<AdminOrders, AdminOrdersViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final AdminOrdersViewHolder holder, final int position, final #NonNull AdminOrders model)
{
holder.userName.setText("Name: "+ model.getName());
holder.userPhoneNumber.setText("Phone Number: : "+ model.getPhone());
holder.userTotalPrice.setText("Total Amount: $"+ model.getTotalAmount());
holder.userDateTime.setText("Order Time: "+ model.getDate() + model.getTime());
holder.userShippingAddress.setText("Shipping Address: "+ model.getAddress() + "," + model.getCity());
holder.showOrdersBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
String uID = getRef(position).getKey();
Intent intent = new Intent(AdminNewOrdersActivity.this, AdminUserProductsActivity.class);
intent.putExtra("uid", uID);
startActivity(intent);
}
});
ordersRef.child(userID).child("fast_delivery").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
TextView switch1 = (TextView) findViewById(R.id.switch1);
switch1.setText(String.valueOf(this));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
And I'm getting this error
java.lang.NullPointerException: Can't pass null for argument 'pathString' in child()
You have a NullPointerException indicating that userID is not initialized, hence this error:
Can't pass null for argument 'pathString' in child()
To solve this, please add the following line of code:
String userID = FirebaseAuth.getInstance().getCurrentUser().getUid();
Right in front of:
ordersRef.child(userID).child("fast_delivery").addValueEventListener(/* ... */);
i guess if im right.. you have created separate tree for orders where you are getting orders
create model class give name as same as childname are where you're getting boolean value of fast_delivery use that boolean value to convert it to string and hence compare that value if String.valueof(boolean)is="true" then print to textview or vise versa with off

Android spinner not showing Firebase Realtime Database data?

I have been having some trouble for quite some time stuck on this. I am wanting to make a spinner in android studio and use a firebase database. But I can't seem to get the spinner to display any of the database's data in the spinner. I have tried to follow some similar questions but I just run into the same problems. Since I am new to Firebase I am unsure how to actually create the indexes to pull from it.
Here is my current code:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference fDatabaseRoot = database.getReference("locations");
fDatabaseRoot.child("buildings").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final List<String> buildings = new ArrayList<>();
for (DataSnapshot buildingSnapshot: dataSnapshot.getChildren()) {
String buildingName = buildingSnapshot.child("buildingName").getValue(String.class);
buildings.add(buildingName);
}
Spinner buildingSpinner = findViewById(R.id.spinner);
ArrayAdapter<String> buildingAdapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_spinner_item, buildings);
buildingAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
buildingSpinner.setAdapter(buildingAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});`
Here is how my database is setup: Firebase Spinner Database
Here is the FirebaseFirestore implementation for SnapshotListener.
You can check the type of change in data (ADDED, MODIFIED, REMOVED) by DocumentChange class. You can check out the example here: https://firebase.google.com/docs/firestore/query-data/listen#view_changes_between_snapshots
FirebaseFirestore db= FirebaseFirestore.getInstance();
db.collection("locations").document("buildings").addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot snapshots,
#Nullable FirebaseFirestoreException e){
//your action here
}
);
Ok so using the Realtime Database I had to switch the Read and Write rules to true, completely forgot to do that.
Remember kids always do your homework. :)

How to save retrieved data from firebase to string variable in android?

Hy Developers, I am new to android development so that's why facing an issue in saving and viewing data to my android app.
I know that data can only be retrieved while you are connected to internet.
But the thing is it is retrieving data and also showing to android log.
But when i try to save it to a string variable or to arraylist to show
it on main activity using that list or variable, its not working.
I am declaring a private string variable to store value from firebase database before onCreate method.
Sorry for my nob question. But this is the issue i am facing.
Following is the code that i am using and some screenshots to make the question understandable.
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Firelog" ;
Button ans1, ans2, ans3, ans4;
TextView uscore, question, timer;
private String mAnswer;
private ArrayList<String> fbquestions = new ArrayList<String>();
private String quest;
private int mScore = 0;
Random r = new Random();
private int res = 0;
private int c = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uscore = (TextView) findViewById(R.id.uscore);
question = (TextView) findViewById(R.id.question);
timer = (TextView) findViewById(R.id.timer);
ans1 = (Button) findViewById(R.id.ans1);
ans2 = (Button) findViewById(R.id.ans2);
ans3 = (Button) findViewById(R.id.ans3);
ans4 = (Button) findViewById(R.id.ans4);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("mcqs");
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Map <String, String> map = (Map)dataSnapshot.getValue();
quest = map.get("question");
fbquestions.add(quest);
Log.v("E_Value","Question is" + quest);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
question.setText(String.valueOf(fbquestions.get(0)));
}
}
In above pic you can see that question is retrieved successfully from firebase and visible in log.
But here when i try to display question on main screen after assigning, its showing blank.
After adding the code to add value to arraylist, application crashes..
You cannot simply get the value of fbquestions.get(0) outside the onDataChange() method because this method has an asynchronous behavior. So you cannot simply create your fbquestions list as a global variable and use it's value outside the callbakc because it will always be empty. Basically, you're trying to use a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended.
A quick solve for this problem would be to move the following line of code:
question.setText(String.valueOf(fbquestions.get(0)));
Inside the callback right after this line of code:
Log.v("E_Value","Question is" + quest);
And your problem will be solved. If you want to use the list outside, I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.
Pass quest value to Textview..
ArrayList<String> questionArrrayList =new Arraylist<>();
questionArrrayList .clear();
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Map <String, String> map = (Map)dataSnapshot.getValue();
quest = map.get("question");
question.setText(quest);
questionArrrayList .add(quest);
Log.v("E_Value","Question is" + quest);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});

get a child name from Firebase Database Progmatically

In Firebase database i have a directory called Global_downloads then inside there are a few children.
child.("Casting apps") which i can locate with in my app code using a String value called AppType.
the next child.("All cast") is the child i need. i can get it into firebase by using an onitem click with my listview. which then sends it to firebase in the form of a child.
but how can i locate the name for the child(Allcast) progmatically? so i can then get the number of downloads?
here is my code for my child listener
#Override
public void onChildAdded(final com.firebase.client.DataSnapshot dataSnapshot, String s) {
String counter = dataSnapshot.child("Global_downloads").child(Apptype).
child("I need this child").child("downloads").getValue(String.class);
Downloadscount.add(counter);
String[] arr3 = Downloadscount.toArray(new String[Downloadscount.size()]);
the rest of the items in the constructor are for other items in my listview
///my custom adapter where it returns the info to my listview
apkData = new dataListAdapter(mContext, arr, arr1, arr2, mrootRef, Apptype,arr3);
mlv.setAdapter(apkData);
apkData.notifyDataSetChanged();
mlv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
final Firebase ref = mrootRef.getRef();
//here is where i assign the name to firebase in my counter class which works
apkNames = AppNameList.get(i).toString(); //this is the name i want to send back to the top and use as a Child name.or can i get the child name another way.
gc = new Global_counter(ref,Apptype,apkNames);
gc.App_DownLoadCounter();
this is my listview there are more items on my list other than Allcast.
but all cast is the only item downloaded. if more items are pressed it adds that name to the list too. the text view you can see is the downloads im trying to add
To get the coresponding item that was downloaded, please use the following line of code inside onItemClick() method and then just use it inside your DatabaseReference.
String downloadName = (String) adapterView.getItemAtPosition(i);
Assuming that Global_downloads node is a direct child of your Firebase root and the value of downloads is of type Integer, to get the number of downloads please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference downloadsRef = rootRef.child("Global_downloads").child(Apptype).child(downloadName).child("downloads");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int downloads = dataSnapshot.getValue(Integer.class);
Log.d("TAG", downloads);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
downloadsRef.addListenerForSingleValueEvent(eventListener);
Your output will be:
0
In your situation, the key is Apptype and the value is downloads.
I'm assuming Global_dowbloads under your root reference.
To get all the downloads with app name, you need to read the data as key->value
Like this
DatabaseReference mRef = FirebaseDatabase.getInstance().getReference();
mRef.child("Global_downloads").child(Apptype)
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot snapshot: dataSnapshot.getChildren()){
Log.v("app_name", snapshot.getKey());
Log.v("app_downloads", snapshot.getValue(String.class));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

Categories

Resources