enter image description hereI want to retrieve temperature values that updating to Firebase by using random key over time. I want to show the temperature value in app according to real time data. I try to use addValueEventListner but seems like the value didnt manage to changes in real time. `public class SecondActivityB extends AppCompatActivity {
private DatabaseReference mDatebase;
private TextView mTempView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_b);
mDatebase = FirebaseDatabase.getInstance().getReference().child("Region 1").child("Parameter Reading").child("temperature");
mTempView = (TextView) findViewById(R.id.tempvalue);
mDatebase.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
String name = dataSnapshot.getValue(String.class);
mTempView.setText("Temperature, C: " + name);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});`}
So the way you are referring to your data is the problem.
your data location is:
hydroponic-monitoring-system / Region 1 / Parameter Reading / KzB1.../temperature
The way you read your data
Region 1 / Parameter Reading / temperature
so you skipped the child (hydroponic-monitoring-system).
The problem you face
now the child (KzB1..) or (KzB2..) these are push keys which means you are not able to refer to them, because you don't know them they are pushed.
Your possible solution is to loop through children like that:
change the:
mDatebase = FirebaseDatabase.getInstance().getReference().child("Region 1").child("Parameter Reading").child("temperature");
into this
mDatebase = FirebaseDatabase.getInstance().getReference().child("hydroponic-monitoring-system").child("Region 1").child("Parameter Reading");
and in your value event listener do this in onDatachange
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
//loop through the keys
for (DataSnapshot datasnap: dataSnapshot.getChildren()){
String name = datasnap.child("temperature").getValue(String.class);
mTempView.setText("Temperature, C: " + name);
}
}
and you should read now the temp at each level of push keys.
Related
I am still new to Studio Android and connecting with Firebase.
I have several pages on the app and trying to collect any typed information through Firebase.
public class faculty_last_respond extends AppCompatActivity implements View.OnClickListener {
private Button submitBtn;
private DatabaseReference fbRef;
private int count = 0;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finalQ = new lastQuestion();
fbRef = FirebaseDatabase.getInstance().getReference("FacultyResponse/User " + count);
fbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists())
count += 1;
}
submitBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String inputTextQ2 = textQ2.getText().toString();
finalQ = new lastQuestion(buttonTextQ1, inputTextQ2, buttonTextQ3, buttonTextQ4, buttonTextQ5);
fbRef.push().setValue(finalQ);
lastPage();
}
});
}
I am trying to store every data under the path "FacultyResponse/User " + count.
(Ex. User0, User1, User2, etc)
Firebase Sample of collecting data under User 0 only
But as seen in the screenshot, the data is still being in under User 0.
I am not quite sure why "count" is not being increased by 1.
I hope I asked the question clearly.
You're only setting fbRef once, and not updating it when you increment count.
fbRef = FirebaseDatabase.getInstance().getReference("FacultyResponse/User " + count);
fbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.exists()) {
count += 1;
dbRef = FirebaseDatabase.getInstance().getReference("FacultyResponse/User " + count);
}
}
But, as commented, sequentially incrementing counters like this are an antipattern in Firebase, and I recommend reading the blog post Best Practices: Arrays in Firebase. Instead of arrays, use Firebase's built-in push() operation to generate auto-incrementing (but non-sequential) keys.
Using that, you end up with this much more idiomatic code:
FirebaseDatabase.getInstance().getReference("FacultyResponse").push().setValue(finalQ);
I am trying to retrieve some data from Firebase, but it is not working for one of my nodes
Note that the UnverifiedEmployees node works fine but the Companies node is not
I am able to see the Log RIGHT BEFORE the Event Listener, but nothing inside of it prints
I am referring to this area:
public void addDataToFirebase() {
Log.i("BEFORE", "BEFORE COMPANIES REF");
companiesRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i("COMPANIESREF", "INSIDE COMPANIES REF ONDATACHANGE");
I have tried this on a different phone. I have tried it on wifi and 4g. I also tried logging in with a different user
I have also tried uninstalling the app from my phone and reinstalling. I have tried writing different implementations of the addListener.
I have also tried looking this up but did not find a lot (e.g. Android Firebase addListenerForSingleValueEvent not called) ( Firebase Android addListenerForSingleValueEvent sometimes not returning data)
Database: (If UserID exists, grab the CompanyID its related to)
Entirety of Code: AddEmployeeActivity.java:
public class AddEmployeeActivity extends Activity {
private EditText firstNameET, lastNameET, phoneNumberET, emailET, ssnET;
private ImageView checkmarkImage;
private static FirebaseUser currentUser;
private static final String TAG = "RealtimeDB";
private FirebaseDatabase database;
private DatabaseReference unverifiedRef, companiesRef;
String emailKey, ssnKey, phoneKey, companyId;
int num;
private FirebaseMethods firebaseMethods;
private Context mContext;
ArrayList<EmployeeUser> myListItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register_addemployees);
mContext = AddEmployeeActivity.this;
firstNameET = (EditText) findViewById(R.id.firstNameET);
lastNameET = (EditText) findViewById(R.id.lastNameET);
phoneNumberET = (EditText) findViewById(R.id.phoneNumberET);
emailET = (EditText) findViewById(R.id.emailET);
ssnET = (EditText) findViewById(R.id.ssnET);
checkmarkImage = (ImageView) findViewById(R.id.checkmarkImage);
database = FirebaseDatabase.getInstance();
unverifiedRef = database.getReference("/Unverified Employees");
companiesRef = database.getReference("/Companies");
currentUser =
FirebaseAuth.getInstance().getCurrentUser();
checkmarkImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final String email = emailET.getText().toString().trim();
final String ssn = ssnET.getText().toString().trim();
final String phone = phoneNumberET.getText().toString().trim();
//Add EditText info to Firebase UnverifiedEmployees Node
addDataToFirebase();
}
});
} //End of ONCREATE
public void addDataToFirebase() {
Log.i("BEFORE", "BEFORE COMPANIES REF");
//companiesRef.addValueEventListener(new ValueEventListener(){
companiesRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i("COMPANIESREF", "INSIDE COMPANIES REF ONDATACHANGE");
EmployeeUser user = new EmployeeUser();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
for (DataSnapshot ds2 : ds.getChildren()) {
for (DataSnapshot ds3 : ds2.getChildren()) {
for (DataSnapshot ds4 : ds3.getChildren()) {
for (DataSnapshot ds5 : ds4.getChildren()) {
Log.i(TAG, "checkIfUsernameExists: datasnapshot: " + ds5);
//user.setCompanyId(ds5.getValue(EmployeeUser.class).getCompanyId());
user.setCompanyId(ds5.getValue(String.class));
Log.i(TAG, "checkIfUsernameExists: ID: " + user.getCompanyId());
//callback.gotDataSnapshot(dataSnapshot);
if (user.getCompanyId() != null) {
companyId = user.getCompanyId();
}
}
}
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.i("Cancelled", "In onCancelled: " + databaseError);
}
//};
}); //END OF ADDLISTENER
// companiesRef.addListenerForSingleValueEvent(eventListener);
emailKey = unverifiedRef.child(currentUser.getUid()).push().getKey();
unverifiedRef.child(currentUser.getUid()).child(emailKey).child("emailAddress").setValue(emailET.getText().toString(), completionListener);
Log.i("getKey EMAIL", emailKey);
ssnKey = unverifiedRef.child(currentUser.getUid()).push().getKey();
unverifiedRef.child(currentUser.getUid()).child(ssnKey).child("socialSecurityNumber").setValue(ssnET.getText().toString(), completionListener);
unverifiedRef.child(currentUser.getUid()).child(ssnKey).child("CompanyID").setValue(companyId, completionListener);
Log.i("getKey SSN", ssnKey);
Log.i("get COMPANY ID", companyId);
phoneKey = unverifiedRef.child(currentUser.getUid()).push().getKey();
unverifiedRef.child(currentUser.getUid()).child(phoneKey).child("phoneNumber").setValue(phoneNumberET.getText().toString(), completionListener);
Log.i("getKey Phone", phoneKey);
}
You cannot achieve this in the way you do. There is no way in which you can get a parent based on the value of one of its childs. With other words, you cannot get the value of L4bs8bH5... if that id RC9zI1... exists beneath it. To solve this, you need to consider using denormalization, which is a common practice when it comes to Firebase. This means that you need to duplicate data in order have those results. For that, I recomend you see this tutorial, Denormalization is normal with the Firebase Database, for a better understanding.
So, in this case you typically should consider augmenting your data structure to allow a reverse lookup. For example, in your scenario, I'd add a list of companies under a userId. Doing this, you'll be able to query all the companies that belong to a single user, if obviously it exists.
I think the problem lies in the references, you're creating.
If you want to get reference to "Unverified Employees" and "Companies" nodes you should create
unverifiedRef = database.getReference("Unverified Employees");
companiesRef = database.getReference("Companies");
instead of
unverifiedRef = database.getReference("/Unverified Employees");
companiesRef = database.getReference("/Companies");
(notice missing slash / sign in the reference string name)
Hope this will help
my data look like this
and I simply want to add an object at index 3. How could I add it there. Is there any way to add an object without iteration or I have to iterate and getChildCount and then append new child("3") and it's data to it.
TransGenderBO transGenderBO = new TransGenderBO();
transGenderBO.setName("pushName");
transGenderBO.setAge(13);
mRef.child("").setValue(transGenderBO);
there is no method in mRef for getting child count and appending new item at 3 position..
Edit after using Frank code but still not working
Query last = mRef.orderByKey().limitToLast(1);
last.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int lastIndex = 0;
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
lastIndex = Integer.parseInt(childSnapshot.getKey());
}
TransGenderBO transGenderBO = new TransGenderBO();
transGenderBO.setName("pushName");
transGenderBO.setAge(13);
mRef.child(""+(lastIndex+1)).setValue(transGenderBO);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(mContext,databaseError.getMessage(),Toast.LENGTH_LONG).show();
}
});
There is a good reason that the Firebase documentation and blog recommend against using arrays in the database: they don't work very well for multi-user applications where users can be offline.
To add the next element to your array here, you'll have to download at the very least the last element of the array to know the index of the next element:
Query last = root.orderByKey().limitToLast(1);
last.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int lastIndex;
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
lastIndex = Integer.parseInt(childSnapshot.getKey());
}
root.child(""+(lastIndex+1)).setValue(true);
}
But this has an inherent race-condition. When multiple users are adding elements to the array at the same time, they may end up writing to the same index.
To prevent this you can use a Firebase transaction. With this you get the current value from a location and in exchange return the new value you want at that location. This ensures that no data is overwritten between users, but means that you have to download the entire array.
And neither of these scenarios works when a user is not connected to the network.
Firebase instead recommends using so-called push IDs, which:
Generate a always-increasing key that is guaranteed to be unique.
Do not require reading any data - they are generated client-side and are statistically guaranteed to be unique.
Also work when a user is offline.
The only disadvantage is that they're not as easily readable as array indexes.
Get your data like this
private ArrayList<TransGenderBO> transGenderBO;
FirebaseDatabase.getInstance().getReference().child("Main")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
transGenderBO = (ArrayList<TransGenderBO>) dataSnapshot.getValue();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
and set your value like this
TransGenderBO transGender = new TransGenderBO();
transGender.setName("pushName");
transGender.setAge(13);
FirebaseDatabase.getInstance().getReference().child("Main").child(String.valueOf(transGenderBO.size())).setValue(transGender);
or U can set this way too
TransGenderBO transGender = new TransGenderBO();
transGender.setName("pushName");
transGender.setAge(13);
TransGenderBO.add(transGender);
FirebaseDatabase.getInstance().getReference().child("Main")
.setValue(transGenderBO);
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
I have an activity and a model called CourseDetails.
String getData;
DatabaseReference mRef = FirebaseDatabase.getInstance().getReference().child("courses").child("Business");
mRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
CourseDetails c = dataSnapshot.getValue(CourseDetails.class);
getData = c.getCourseName();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
textview1.setText(getData);
Using above code throws NullPointerException at last line above. But if I put textview1.setText(getData) into the ValueEventListener, under getData = c.getCourseName(), the data can be displayed correctly.
Methods I found working are using SharedPreferences or setting data from a method such as public void display(String data) { textview1.setText(data); }. But what are the other ways to keep the retrieved data even if the data is outside ValueEventListener?
For instance I want to persist the data added into an ArrayList.
ArrayList<String> listData;
DatabaseReference mRef = FirebaseDatabase.getInstance().getReference().child("courses").child("Business");
mRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CourseDetails c = dataSnapshot.getValue(CourseDetails.class);
String code = c.getCourseCode();
String name = c.getCourseName();
String CodeName = code + " " + name;
listData.add(CodeName);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// data in ArrayList should be able to display here
StringBuilder builder = new StringBuilder();
for (String s : listData) {
builder.append(s + "\n");
}
textview1.setText(builder.toString());
How to achieve this kind of persistence?
As per my understanding, Firebase will notify all it's data listener attached to specific references (database references wherever the addValueEventListener is added) when those specific data gets modified. That is when
onDataChange will be called, when there is modification of the data at those database references,
(besides modification the method will always be called first time).
And this happens
asynchronously, so in the first case where null occurs because we don't know whether data is retreived from Firebase and
as far as I know, Android's main thread cannot be put on hold or pause until we retreive the data that's why we use Asynchronous tasks in Android.
So, I think the best way to do specific updates or task on data change is within onDataChange method. So, like you stated it could be
done by making those changes within onDataChange itself or by calling some other method from onDataChange.
Or, if you are using
adapter then, notifying adapter about the change within onDataChange. Also, you can take a look at other choice i.e. FirebaseRecyclerAdapter then,
it will handle the update automatically without any extra effort.