I am trying to make it so that when a user creates an open game, in my Firebase Database the name of the game is the size of the list. So the very first game created the name of it will = 0, and if another user creates a game then the game will be labeled 1 and so on.
I have it set up right now so that the games are labeled the size of the game list, but the list isn't really updating. The games keep getting called '0' because it thinks the list is empty even though I have visual confirmation in the app that there are items being added to the list.
So my question is: How can I make it so the list continuously updates each time a game is added, and how can I make it so that it updates for all users and not just the user who created the game?
This is what I have setup right now. Here are the variables I am using for the list and the integer getting the list size
ArrayList<String> openGames = new ArrayList<>();
int gameSlot = openGames.size();
Here is what I use to name the game when it is created.
gameMaker = new GameMaker(hp.uid, userName, wagerD, gameSlot);
FirebaseDatabase.getInstance().getReference("FCGames").child(Integer.toString(gameSlot))
.setValue(gameMaker).addOnCompleteListener...
And this is what I have to add the game to the list.
cgRef.child(Integer.toString(gameSlot)).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
openGames.add(userName);
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
So again my question is how can I make this list update correctly and how can I make it update for all users on the app?
Edit
Here is what I did with my onChangeData
cgRef.child(Integer.toString(gameSlot)).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
wager = (String) dataSnapshot.child("wager").getValue();
gameSlot = openGames.size();
adapter.notifyDataSetChanged();
}
and now the openGames.add is in my createGameLobby method.
FirebaseDatabase.getInstance().getReference("FCGames").child(Integer.toString(gameSlot))
.setValue(gameMaker).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
openGames.add(userName);
Toast.makeText(FlipCoinLobby.this, "Game creation successful.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(FlipCoinLobby.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
^^ that is just the important snippit from the method. And then I have an onClickListener that creates that calls that method when a button is pressed
In below code segment, you did that openGames.add(username) in onDataChange listener. I think it is an incorrect use of this ondatachange function
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
openGames.add(userName);
adapter.notifyDataSetChanged();
}
please use this to get data from db and update your data. Then push your data to db. You didn't use snapshot value also. You can get most recently updated data from dataSnapshot . Use it to update user data then push it to db
Related
So, I am using android studio to make an app that displays data stored in firebase real-time database. The app is simple, it displays the name and phone number from firebase to the app.
The app works fine and even displays the data but the only thing is it displays the data/values with curly braces and an equal sign (like a JSON format) is there anyway I can make it display just the desired values and not the extra signs and punctuation
Code:
ArrayList<String> list =new ArrayList<>();
ArrayAdapter adapter = new ArrayAdapter<String>(this, R.layout.list_view, list);
listView.setAdapter(adapter);
DatabaseReference ref= FirebaseDatabase.getInstance().getReference().child("Car Wash");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
list.clear();
for(DataSnapshot snapshot: dataSnapshot.getChildren()){
list.add(snapshot.getValue().toString());
}
adapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
What you're seeing is the toString() output of the value a Firebase DataSnapshot that represents an object with multiple values.
You'll want to get the individual values from that snapshot, and display their values with something like this:
String name = snapshot.child("Name").getValue(String.class);
String phoneNr = snapshot.child("Phone Number").getValue(String.class);
list.add(name+" ("+phoneNr+")");
I want to make two database calls one inside the other and make use of the first call data. Since firebase database calls are asynchronous this is not behaving the way I want.
I HAVE two database nodes Users, Chats.
I want first query through one Users at a time and take the user id and then query through the Chats model and check if the id in Users and Chats nodes are same
Something like this.
database.getReference().child("Users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
list.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
users = dataSnapshot.getValue(Users.class);
users.setUserId(dataSnapshot.getKey());
database.getReference().child("Chats").child(auth.getUid() + users.getUserId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()){
//ADD USER TO LIST UPDATE UI
list.add(users);
}
else{
//DON'T ADD USER
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Hope I made the problem clear.
In Firebase, I list my data by auto increment. However, when i any data is deleted, i can't new data added. Updating is being made on the last added data. I need a solution for this.
Firebase
My Source:
public class MainActivity extends AppCompatActivity {
EditText name_et;
Button button_save;
FirebaseDatabase firebaseDatabase;
DatabaseReference databaseReference;
long autoincrementid =0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
name_et = findViewById(R.id.aaaa);
button_save = findViewById(R.id.btnsave);
databaseReference = firebaseDatabase.getInstance().getReference().child("Data");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists());
autoincrementid=(snapshot.getChildrenCount());
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
button_save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String a = name_et.getText().toString();
databaseReference.child(String.valueOf(autoincrementid+1)).setValue(a);
Toast.makeText(MainActivity.this, "+++++", Toast.LENGTH_SHORT).show();
}
});
}
}
Right now you use the count of children to determine what the next number is. That works well if all sequential indexes are occupied, but (as you found) not when you delete one of more indexes in there.
The proper solution in that case depends on what you want to happen. I know of these general use-cases:
You want the list to behave like an array, which means that when you remove #3 in your JSON, the #4 and #5 actually get a new index. This will require you to change all other items when you remove one. For more on this see the answer I gave just now to another question: Firebase Remove with Javascript
You want to have an always increasing sequential index, typically referred to as a sequence or auto-increment values in relational databases. If you want this, you'll have to store the latest index that you handed out somewhere separate in the database and transactionally update that whenever you add an item to the list.
You want to put new items at the first available index, reusing the indexes of any deleted nodes. This seems to be your use-case, so we'll look at that further below.
Possible code for a solution that finds the first available id:
databaseReference = firebaseDatabase.getInstance().getReference().child("Data");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
int autoincrementid = 0;
do {
autoincrementid++;
} while (snapshot.hasChild(""+autoincrementid));
snapshot.child(""+autoincrementid).setValue("New value");
})(
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // never ignore errors
}
});
A few notes on this code:
I didn't run it, so there may well be some minor errors in there. If you get any of those, please try to figure them out on your own and edit the answer to include the solution.
You probably should use a transaction here to ensure there are no conflicting updates. The logic of the loop will be the same though.
I'm calling addValueEventListener inside the button click, but this method only reads the last item in the node. I want to read all the child value in the node What went wrong here?
btnorder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot dataSnapshot1:dataSnapshot.getChildren())
{
SelectedItems si=dataSnapshot1.getValue(SelectedItems.class);
si.getItemname();
Toast.makeText(MyBookedItems.this, ""+si.getItemname(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
I think you can create an array list and put all snapshot data into it, and then you can find the last data of the list with the value you find by subtracting one from the length of the list. Sorry for my bad English :( I have tried to explain in the solution in the code below)
ArrayList<SelectedItems> selectedItems = new ArrayList<SelectedItems>();
for(DataSnapshot dataSnapshot1:dataSnapshot.getChildren())
{
SelectedItems si=dataSnapshot1.getValue(SelectedItems.class);
selectedItems.add(si);
}
selectedItems.get(selectedItems.size());
It's read all the values but I got the output as a Toast message, because of that I only see the last value)
I'm a beginner in Android programming and creating multiplayer game using firebase. I'm thinking of the logic of how users can start the game.
What I am trying to do is to show Toast when the room the users play the game gets full. But I'm wondering how other devices can tell if the room gets full. I thought addListenerForSingleValueEvent for this but it doesn't work as I expected.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
String roomName = getIntent().getExtras().getString("ROOM_NAME");
thisRoom = FirebaseDatabase.getInstance().getReference().child(roomName);
thisRoom.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//when the room gets full, start the game
int numberOfPlayers = (int) dataSnapshot.getChildrenCount();
if (numberOfPlayers >= 2) {
Toast.makeText(MultiplayerStreetViewActivity.this, "Game Starts", Toast.LENGTH_LONG).show();
//do something
}
}
I checked if it works using two emulators. And for the first player that started the activity earlier, Toast doesn't show up when the second value is added. How can devices check when the new values added automatically?
I'm sure I misunderstand something and make dumb mistake.. How can I do what I want to do?
I have an idea, that is add child event listener for thisRoom and use an array list on local device to manage players in the room. Each time you add, or modify, or remove player in the rooms. The listener will triger immediately and you can add, or modify, or remove on the array list. So, you can know if the room full or not( base on your array list full or not).
thisRoom.addChildEventListener (new ChildEventListener(){
public void onCancelled(DatabaseError error)
{
//say something to player
}
public void onChildAdded(DataSnapshot snapshot, String previousChildName)
{
Player newPlayer = snapshot.getValue(Player.class);
//then add newPlayer to local array list
}
public void onChildChanged(DataSnapshot snapshot, String previousChildName)
{
Player changedPlayer = snapshot.getValue(Player.class);
//then do something to modify info of the player in the array list
}
public void onChildMoved(DataSnapshot snapshot, String previousChildName)
{
//I have no idea for this method
}
public void onChildRemoved(DataSnapshot snapshot)
{
//remove player from your array list
}
});