Firebase Event Listener never triggered - android

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

Related

How can I make the "count" keep increasing without the "count" starting 0 again

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);

Cannot get the value out of firebase with .getValue()

I am new to Java, Android, and Firebase. What I am trying to do here is read what's already uploaded to firebase, but the code doesn't work. I put a breakpoint and found that it doesn't even run the listener. What is the problem here? Any help is much appreciated.
Here is my database on Firebase:
This is the code I used to retrieve the information from the database.
//in Main Activity
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
//Rest of the code is within onCreate()
mDatabase.child("9099").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String number = dataSnapshot.child("Number").getValue().toString();
String time = dataSnapshot.child("Time").getValue().toString();
String chan1 = dataSnapshot.child("Channel1").getValue().toString();
String chan2 = dataSnapshot.child("Channel2").getValue().toString();
testing.setText(String.format(time));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

Retrieving child value across random key -Firebase

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.

Searching firebase if a value exists or not

I have the following data structure in my firebase. I am implementing a coupon based system where you enter a code in dialogue box and it is searched across the database. So I have been trying to figure out this but I haven't found the perfect query that can search the code, if found, then get all the other child values too.
Below is the code that i have been trying with:
private void couponsearch() {
final EditText taskEditText = new EditText(this);
AlertDialog.Builder dialog = new AlertDialog.Builder(this)
.setTitle("Akiba Yangu")
.setMessage("Enter Akiba Code Here.")
.setIcon(R.drawable.akyi)
.setView(taskEditText).setPositiveButton("SAVE",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
String stringe = taskEditText.getText().toString();
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("codes").orderByChild("code").equalTo(stringe).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Coupons coo = dataSnapshot.getValue(Coupons.class);
String name = dataSnapshot.getKey();
int codez = coo.getValuee();
code.setText(name);
if(dataSnapshot != null && dataSnapshot.getChildren().iterator().hasNext()){
for(DataSnapshot ds : dataSnapshot.getChildren()) {
codegotten();
}
}else {
nocode();
}
int val = coo.getValuee();
Akibasavings as = new Akibasavings();
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
System.out.println(val);
code.setText(name);
as.setName(name);
as.setAmount(val);
final Firebase ref = new Firebase("https://akiba-c9600.firebaseio.com/");
Firebase newRef = ref.child("Savings"+uid).push();
newRef.setValue(as);
sendNotification();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
public void onCancelled(FirebaseError firebaseError) {
//Username Does Not Exist
}
});
}
});
dialog.show();
}
I would like to search the code, check if it is really there or not: if it is there I need to get all the other values too, i.e there are three nodes in every child. code, brand, value. After I have checked that the code exists, I would like to also get the other values associated with it. Regards
To achieve this, i recomand you change the structure of your database a little bit by adding a new node named coupons. Your database should look like this:
Firebase-root
--- coupons
TTUUPP: true
KKLLOO: true
To check if a coupon exists in your database, just add a listener on the new created node and use exists() method. This is a coomon practice within Firebase named denormalization and is for simplify and reduce query and bandwith. This what you need.
What you need is Query.
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
Query mQuery = mDatabase.child("codes").orderByChild("code").equalTo(stringe);
mQuery.addListenerForSingleValueEvent(new ValueEventListener() {
// use single value event listener to detach listener immediately after query
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
// code exists, cast your data to relevant object
// note that if multiple entries exists, you need to loop through them
} else {
// code does not exists
}
}
});
Read the official document here.
Note that you must remember to index your firebase properly! Query on firebase is not the same as local database query. If you do not index your firebase, the query will download everything under the codes section into user phone, before doing the search locally on user phone. This will consume high bandwidth and memory. Learn more about index here. Read about my personal issue with index previously here.
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
Your onDataChange() needs to handle the fact that the snapshot contains a list of result by looping over DataSnapshot.getChildren():
mDatabase.child("codes").orderByChild("code").equalTo(stringe).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
Coupons coo = childSnapshot.getValue(Coupons.class);
String name = childSnapshot.getKey();
int codez = coo.getValuee();
code.setText(name);
...
}
}

Get element by key with Firebase

I've been trying to retrieve an element from my Firebase database using its key. I have a class User and users are present in database.
I want to retrieve an object user using its key with this method :
public User getConnectedUserByUId(final String uid){
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users");
final List<User> connectedUser= new ArrayList<User>();
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot item: dataSnapshot.getChildren()) {
if (item.getKey()==uid)
{
User user= dataSnapshot.getValue(User.class);
connectedUser.add(user);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return connectedUser.get(0);
}
but it returns an empty list every time.
The issue is here:
if (item.getKey()==uid)
since you are comparing 2 String in java you have to use the method
string.equals(Object other) not the == operator.
Moreover, since you know the key of the data in Firebase you can use it to get the reference without cycling all children.
Something like:
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users").child(uid);
Here you try to check a very specific ID only on changed data. Instead, try using a Firebase Query with filterByKey and not using your own function to achieve that. Here's sample code that I would use to try to replace your function:
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users");
Query connectedUser = ref.equalTo(uid);
connectedUser.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
// TODO: handle the post here
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
});
As specified in the Firebase documentation here: https://firebase.google.com/docs/database/android/lists-of-data#filtering_data
in the line : User user= dataSnapshot.getValue(User.class);
you have to put : User user= item.getValue(User.class);
and you have to check the id after you get the user:
if (user.getKey()==uid){
connectedUser.add(user);
}
There are 2 mistakes and a minor issue:
you are using == to compare two String objects. In java, this is true only if they are the same reference. Use equals instead.
addValueEventListener only adds a listener that gets invoked once after you add it and then every time something changes in the value you are listening to: this is an asynchronous behaviour. You are trying to get data synchronously instead. Please read something about this.
you are fetching useless data: you only need an object but you are fetching tons of them. Please consider to use the closest reference you can to the data you are fetching.
So, in conclusion, here's some code. I'd like to point out right now that forcing synchronous acquisition of naturaly asynchronous data is a bad practice. Nevertheless, here's a solution:
public User getConnectedUserByUId(final String uid){
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
DatabaseReference ref = database.child("users").child(uid);
Semaphore sem = new Semaphore(0);
User[] array = new User[1];
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot item: dataSnapshot.getChildren()) {
if (item.getKey()==uid)
{
User user= dataSnapshot.getValue(User.class);
array[0] = user;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
try
{
sem.tryAcquire(10, TimeUnit.SECONDS);
}
catch (Exception ignored)
{
}
return array[0];
}
EDIT: I've just seen that this post is very old. I'm not sure how I ended up here.

Categories

Resources