I have 2 DatabaseReference:
1 is "Active" child
2 is "Finish" child
I want to MOVE child from "active" to "finish", but I wasn't able to do it. Any ideas how? Thanks.
I have this code:
public class SingleGameActivity extends AppCompatActivity {
private DatabaseReference mDatabaseActivGame;
private DatabaseReference mDatabaseFinishGame;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_game);
game_key = getGameKey();
mDatabaseActivGame = FirebaseDatabase.getInstance().getReference().child("Games").child("Active").child(game_key);
mDatabaseGame.keepSynced(true);
mDatabaseFinishGame = FirebaseDatabase.getInstance().getReference().child("Games").child("Finish").child(game_key);
mDatabaseGame.keepSynced(true);
...
Inside Active child, I have game_key and inside, multiple child values.
I want to move it to finish because the recyclerview shows me the active child. Thanks!
Following code will read value from "your-project-root/Games/Active/game_key"
// mDatabaseActivGame is still the same like in your sample
mDatabaseActivGame.addListenerForSingleValueEvent(new ValueEventListener() {
... onDataChange(DataSnapshot dataSnapshot) {
// data is in dataSnapshot object
// do something here
}
...
});
Then following code will write data in "your-project-root/Games/Finish/game_key"
// mDatabaseFinishGame is still the same like in your sample
mDatabaseFinishGame.setValue(yourValueHere);
So combine them we get code like this:
mDatabaseActivGame.addListenerForSingleValueEvent(new ValueEventListener() {
... onDataChange(DataSnapshot dataSnapshot) {
mDatabaseFinishGame.setValue(dataSnapshot);
}
...
});
I haven't test this myself but in theory it should work. Hope this helps
Related
In our database structure, each "User" holds multiple bid-Ids, each bid-Id represents an entry point in the "Jobs" database.
Currently when we want to iterate through all jobs of a single person the code looks something similar to:
final DatabaseReference mDatabaseJobs = FirebaseDatabase.getInstance().getReference().child("Jobs");
DatabaseReference mDatabaseUser = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUser.getUid());
mDatabaseUser.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
DataSnapshot userBids = dataSnapshot.child("listOfBids");
final int num_user_bids = (int) userBids.getChildrenCount();
for(final DataSnapshot job : userBids.getChildren()){
String jobId = job.getValue(String.class);
mDatabaseJobs.child(jobId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
bid_count.addAndGet(1);
Here is the database structure, the objective is somehow to get all the jobs of a specific person.
Is there a way to retrieve all the jobs at once? mabye a list of keys? and not calling the add-listener for each one?
If not, I know that firebase fetches the data asynchronously, but does it do it in parallel?
i.e we currently increment an atomic integer to know whether firebase has already fetched all the jobs, because we don't want to threads to increment the counter at the same time, is it necessary in our current implementation?
Thanks!
You can keep a HashMap outside the "Users", populate it with current user's list of jobs. Then attach another listener to "Jobs" and iterate over your hashMap and grab the specific jobs you want. Below is a reference code:
HashMap<Integer, String> listOfJobs = new HashMap<>();
DatabaseReference mDatabaseUser = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUser.getUid()).child("listOfBids");
mDatabaseUser.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists) {
listOfJobs.putAll((Map) dataSnapshot.getValue());
}
// Here you can add a listener to the entire "Jobs" reference like this
DatabaseReference mDatabaseJobs = FirebaseDatabase.getInstance().getReference().child("Jobs");
mDatabaseJobs.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot userDataSnapshot) {
if (userDataSnapshot.exists) {
for (String jobId : listOfJobs.values()) {
if (userDataSnapshot.hasChild(jobId) {
DataSnapshot job = userSnapshot.child(jobId);
// here you can use job snapshot
bid_count.addAndGet(1); // something like this?
}
}
}
}
});
Basically, you are adding a listener to something that is not nested or deep and using the loop to get the children, instead of adding a listener to nested children.
Hope this helps.
So I am currently developing an API which gets data from Firebase and depending on that data the button changes its color. However, when I tried to make a new structure for my buttons. It won't let me make one.
I tried the answers here: How to insert data of two tables in Firebase? and here: How can I create an empty table from android app in Firebase? but neither did work for me.
Here's my sample code:
public class Normal extends AppCompatActivity {
Button suite, normal, room1;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mToggle;
private DatabaseReference mFirebaseDatabase1;
private FirebaseDatabase mFirebaseInstance;
//FIREBASE AUTH FIELDS
DatabaseReference mSearchedLocationReference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal);
mFirebaseInstance = FirebaseDatabase.getInstance();
//FIREBASE
mFirebaseDatabase1 = mFirebaseInstance.getReference("Rooms");
mSearchedLocationReference = mFirebaseDatabase1.child("Room1").child("RoomStatus");
//ASSIGN ID's
room1 = (Button) findViewById(R.id.room2);
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mFirebaseDatabase1.child("Rooms").child("Room1").child("RoomStatus").setValue("Green");
startActivity(new Intent(Normal.this, room2.class));
}
});
mSearchedLocationReference.addValueEventListener(new ValueEventListener() { //attach listener
#Override
public void onDataChange(DataSnapshot dataSnapshot) { //something changed!
for (DataSnapshot locationSnapshot : dataSnapshot.getChildren()) {
String location = locationSnapshot.getValue().toString();
Log.d("Locations updated", "location: " + location); //log
if ( location.equals("Green")){
room1.setBackgroundColor(Color.GREEN);
}else if ( location.equals("Red")){
room1.setBackgroundColor(Color.RED);
}
else{
room1.setBackgroundColor(Color.YELLOW);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) { //update UI here if error occurred.
}
});
}
}
PS: I created the User structure (which is for my login) on another class.
I think you should make a new structure at firebase you can do it by clicking the "+" beside your DB Name, here's an example:
Implement your methods and it should work. Then Connect again your firebase database.
I think the problem is when you are changing the value when (room 1) is clicked. You already declared this reference like this:
mFirebaseDatabase1 = mFirebaseInstance.getReference("Rooms");
when you clicked the button (room 1) you triggered this reference to change value :
mFirebaseDatabase1.child("Rooms").child("Room1").child("RoomStatus").setValue("Green");
In other words
you are saying that you want to access
Rooms/Rooms/Room1/RoomStatus/Green
but you should be looking for this
Rooms/Room1/RoomStatus/Green
you have an extra child called Rooms that is repeated and causing the problem
Possible Solution
do this in the click listener of room 1
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mFirebaseDatabase1.child("Room1").child("RoomStatus").setValue("Green");
startActivity(new Intent(Normal.this, room2.class));
}
});
I just removed the extra(.child("Rooms")).
What i think is going wrong is that an array is returning and its last item is green
for (DataSnapshot locationSnapshot : dataSnapshot.getChildren())
that is not letting you change the color of the button .
we will be able to help you if you show the model of your database .
I'm trying to get a user's profile from a Firebase DB. Then using the user's information I want to set TextViews in my Fragment's layout to reflect the user's individual stats.
The problem is that the rootViw is being returned prior to having recieved the user's profile. And so I get a null object reference error.
My understanding of the fragment's life cycle is that onCreate() is created first and so I tried placing the DB code there but I get the same problem. I then figured that if accessing the DB is slower than my onCreateView() I'll place a Thread.sleep() timer to wait for the DB call to complete and then perform the rest of my code. Which I know is a stupid solution but just wanted to test my theory; that also failed so obviously my understanding is wrong.
Where should I place my DB call so that it completes prior to returning my rootView? Why does placing the DB listener in OnCreate() not work and why does the Thread.sleep() delay not work?
Leaderboard Fragment
public class Leaderboard extends Fragment{
private FirebaseAuth mFirebaseAuth;
private DatabaseReference mUserDatabaseReference;
private User user;
private TextView scoreView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_leaderboard,
container, false);
scoreView = rootView.findViewById(R.id.leaderboard_score);
mFirebaseAuth = FirebaseAuth.getInstance();
final String userUID = mFirebaseAuth.getCurrentUser().getUid();
mUserDatabaseReference =
FirebaseDatabase.getInstance().getReference("users");
mUserDatabaseReference.addListenerForSingleValueEvent(new
ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.hasChildren()) {
for (DataSnapshot messageSnap: snapshot.getChildren()) {
if(messageSnapshot.getKey().equals(userUID)) {
user = messageSnapshot.getValue(User.class);
}}}}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
//Causes error because user==null
scoreView.setText("Score: " + user.getScore());
return rootView;
}
}
All Firebase APIs are asynchronous. You should expect that listeners may be called after any amount of time, based on the quality of the hardware and its network connection. Don't ever use Thread.sleep() to try to control the timing of things - that is an anti-pattern.
My suggestion to you is to inflate a "loading" screen in onCreateView() to display immediately, so the user doesn't have to look at a blank screen when your fragment starts. Then, when your listener is called with the data you want to display, add or update other views as needed.
Why not set the score after you get the DB result ?
mUserDatabaseReference.addListenerForSingleValueEvent(new
ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (snapshot.hasChildren()) {
for (DataSnapshot messageSnap: snapshot.getChildren()) {
if(messageSnapshot.getKey().equals(userUID)) {
user = messageSnapshot.getValue(User.class);
}
}
scoreView.setText("Score: " + user.getScore());
}}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
I'm very new to Java, so apologies upfront if this is super straight forward.
I'm tying to loop through my Firebase database and store key set of every child in an ArrayList.
Here is the short version of the code:
public class MainActivity extends AppCompatActivity {
private DatabaseReference mRefEvents;
private List<String> newArray;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRefEvents = FirebaseDatabase.getInstance().getReferenceFromUrl("https:***");
newArray = new ArrayList<String>();
mRefEvents.addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
for (DataSnapshot child : dataSnapshot.getChildren())
{
for (DataSnapshot grandChild : child.getChildren())
{
newArray.add(grandChild.getKey());
}
}
Log.i("App info middle", newArray.toString());
}
#Override
public void onCancelled(DatabaseError databaseError)
{
}
});
Log.i("App info end", newArray.toString());
}
}
When I log ("App info middle") newArray within addValueEventListener method, I get exactly the values I need. However, the second log ("App info end") at the bottom, gives me an empty array and doesn't store keys into ArrayList newArray.
I'm sure I'm missing something simple, but any suggestions would be highly appreciated. Thanks!
This looks like you are running everything in one go. Since the listener runs asynchronously, I imagine that you are hitting the Log at the bottom "App Info End" before you are hitting the Log in the listener "App Info Middle". Try running "App info End" in a different method or after a button click and you should see the Array populated. Having said all this, can you post your output to the Console so we can confirm that the App Info End is being hit before App info Middle?
I'm building an app that is basically a table for soccer that updates every time I change it in my DB.
I'm using Firebase in this way:
I'm trying to use an addValueEventListener, but I don't know which one of the values is the one that changes (dif,score,points...) therefore I don't which field in my table I should update.
public class table extends AppCompatActivity {
Button insert;
TextView name, games, win, lost, tie, score, dif, points;
Team A;
DatabaseReference mRootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference FootballRef = mRootRef.child("Football");
DatabaseReference HouseARef = FootballRef.child("HouseA");
protected void onStart() {
super.onStart();
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
String key = dataSnapshot.getKey() ;
Toast.makeText(table.this,key, Toast.LENGTH_SHORT).show();
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
// ...
}
};
HouseARef.addValueEventListener(postListener);
}
}
See here, when let's say I'm updating the name of housaA, I want to get back the key that got updated (in my case, name), but when I'm using
dataSnapshot.getKey() the Toast I'm getting back is HouseA and not name.
You won't be able to do this using a valuelistener.
Instead put a childeventlistener on the houseA.
Now inside onChildChanged, you should get the child node under houseA which has changed as a datasnapshot and from this snapshot, you can get the key which has changed