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/
Related
How to display new data at the top position of an adapter? Here are the coding:-
Sorry just now, I wrongly copy the coding, now I just noticed. Sorry my bad. The issues now is I want to display the latest advertisement at the top of the adapter....
mDatabase.child("Advertisement").child(mAuth.getUid()).addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot)
{
//iterating through all the values in database
mChildrenList = new ArrayList<>();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren())
{
Advertisement advertisement = postSnapshot.getValue(Advertisement.class);
mChildrenList.add(advertisement);
}
//Creating adapter
mAdapter = new AdvertisementAdapter(getApplicationContext(), mChildrenList, "AddAds");
//Adding adapter to recyclerview
mRecyclerView.setAdapter(mAdapter);
//mAdapter.notifyItemChanged(0);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError)
{
}
});
This line:
tuitionPackageList.add(0, new TuitionPackage(tuitionPackageList));
you get an error because you are instantiating a TuitionPackage object with tuitionPackageList as a parameter and I believe this is not correct.
Earlier in the code you made the same instantiation with just:
TuitionPackage tuitionPackage = new TuitionPackage();
and you added the item to the end of the list.
Is it this item that you wanted to add at position 0?
Edit change to this:
else {
TuitionPackage tuitionPackage = new TuitionPackage();
tuitionPackage.setPrice(mPriceView.getText().toString());
tuitionPackageList.add(0, tuitionPackage);
mPackageAdapter.notifyItemInserted(0);
}
replace last else block with this
TuitionPackage tuitionPackage = new TuitionPackage();
tuitionPackage.setPrice(mPriceView.getText().toString());
tuitionPackageList.add(tuitionPackage);
mPackageAdapter.notifyDataSetChanged();
Here are my answer with the help from the above coding to sort the first ads at the top position:-
//Iterating through all the values in database
mChildrenList = new ArrayList<>();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren())
{
Advertisement advertisement = postSnapshot.getValue(Advertisement.class);
mChildrenList.add(0, advertisement);
}
//Creating adapter
mAdapter = new AdvertisementAdapter(getApplicationContext(), mChildrenList, "AddAds");
//Adding adapter to recyclerview
mRecyclerView.setAdapter(mAdapter);
mAdapter.notifyItemInserted(0);
Thanks for helping. I am creating an Android app which is working perfectly well. But I am facing a minor problem. The application contains message functionality for the posted ads. When the user opens an ad he is greeted with two options of call or message, where if the user clicks on the message button then he is sent to the chat screen, at the time of the button press the info gets stored in firebase database but I want the info to get stored only for the first time and if the users clicks the button next time then he should be taken to the pre-generated node, not on the new one.
Below is my code for adding the new nodes on the click of the button. Please lemme know if there is any way through which I can stop nodes from getting generated on every button click:
mChat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent chatIntent = new Intent(ExpandActivity.this, ChatActivity.class);
chatIntent.putExtra("user_id", mId);
chatIntent.putExtra("user_name", mName);
chatIntent.putExtra("ad_id", user_id);
chatIntent.putExtra("cow", m);
startActivity(chatIntent);
mRootRef.child("Chat").child(uid).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
DatabaseReference user_message_push = mRootRef.child("Chat").child(uid).push();
m = user_message_push.getKey();
if (!dataSnapshot.hasChild(user_id)) {
mRootRef.child("AdvertData").child(user_id).addValueEventListener(new
ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String image = dataSnapshot.child("image").getValue().toString();
String title = dataSnapshot.child("title").getValue().toString();
String price = dataSnapshot.child("price").getValue().toString();
Map chatAddMap = new HashMap();
chatAddMap.put("seen", false);
chatAddMap.put("timestamp", ServerValue.TIMESTAMP);
chatAddMap.put("image", image);
chatAddMap.put("title", title);
chatAddMap.put("price", price);
chatAddMap.put("chatUser", mName);
chatAddMap.put("ads", user_id);
chatAddMap.put("chatUserId", mId);
Map chatAddMap1 = new HashMap();
chatAddMap1.put("seen", false);
chatAddMap1.put("timestamp", ServerValue.TIMESTAMP);
chatAddMap1.put("image", image);
chatAddMap1.put("title", title);
chatAddMap1.put("price", price);
chatAddMap1.put("chatUser", name);
chatAddMap1.put("ads", user_id);
chatAddMap1.put("chatUserId", uid);
Map chatUserMap = new HashMap();
chatUserMap.put("Chats/" + uid + "/" + m, chatAddMap);
chatUserMap.put("Chats/" + mId + "/" + m, chatAddMap1);
mRootRef.updateChildren(chatUserMap, new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError != null) {
Log.d("CHAT_LOG", databaseError.getMessage().toString());
}
}
});
Below is the picture of how my database looks like:
Here is the logic..! Use addListenerForSingleValueEvent. It is called only one time. And Get key only if snapshot doesn't exist
DatabaseReference user_message_Ref = mRootRef.child("Chat").child(uid);
// First check if snapshot exist()
user_message_Ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists())
{
// GO TO THE DESIRED ACTIVITY
navigateToYOURActivity();
}else
{
// GET KEY
String key = user_message_Ref.push().getKey();
// & UPDATE DATABASE
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
I want the info to get stored only for the first time and if the
users clicks the button next time then he should be taken to the
pre-generated node
It's probably because of addValueEventListener().
You can try using addListenerForSingleValueEvent() which does this only one time i suppose.
When you are using the following lines of code:
DatabaseReference user_message_push = mRootRef.child("Chat").child(uid).push();
m = user_message_push.getKey();
You are generating a new random id at every button click. This is what push() method does. If you want the second time you click the button to access the same reference, you should store that id in a variable and use the same variable again, not generate another one.
Hi I am new to Android and Firebase. I am trying to loop through the TextViews and updating the values from the database.
I got a simple database and would like to display all the keys (eg 71001) on multiple textviews.
I got my views instantiated as below:
// Instantiate Views for Rolls:
mRoll1 = findViewById(R.id.rollno1);
mRoll2 = findViewById(R.id.rollno2);
mRoll3 = findViewById(R.id.rollno3);
mRoll4 = findViewById(R.id.rollno4);
mRoll5 = findViewById(R.id.rollno5);
mRoll6 = findViewById(R.id.rollno6);
mRoll7 = findViewById(R.id.rollno7);
mRoll8 = findViewById(R.id.rollno8);
This will only put the last number in the text view
// Read from the database
mRootReference.addListenerForSingleValueEvent (new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
mRolll.setText(snapshot.getKey());
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
//Failed to read value
}
});
Please help.
What it looks like right now is that you end up with just having 71008 in your first TextView because you loop through the keys but only ever access the first TextView.
If you know that you'll always have eight keys, in your case you can try adding them to your TextViews without the loop, something along the lines of:
// Read from the database
mRootReference.addListenerForSingleValueEvent (new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
Iterator<DataSnapshot> children = dataSnapshot.getChildren().iterator();
mRolll.setText(children.next().getKey());
mRoll2.setText(children.next().getKey());
mRoll3.setText(children.next().getKey());
mRoll4.setText(children.next().getKey());
mRoll5.setText(children.next().getKey());
mRoll6.setText(children.next().getKey());
mRoll7.setText(children.next().getKey());
mRoll8.setText(children.next().getKey());
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
//Failed to read value
}
});
If you want to use a loop, I would recommend placing your TextViews in an Array or List and then looping through those with the children:
// Read from the database
mRootReference.addListenerForSingleValueEvent (new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
Iterator<DataSnapshot> children = dataSnapshot.getChildren().iterator();
TextView[] views = new TextView[] {
mRolll,
mRoll2,
mRoll3,
mRoll4,
mRoll5,
mRoll6,
mRoll7,
mRoll8,
}
for (int i = 0; i < views.length && children.hasNext(); i++) {
views[i].setText(children.next().getKey());
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
//Failed to read value
}
});
(The Array could be created elsewhere, probably in the same place you instantiate your Views)
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.
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) {
}
});