Error when trying to call method - Cannot be applied to () - java

Image of DB structure
I have currently created a method for updating a book using Firestore. I am attempting to call this method in onOptionsItemSelected.
I am relatively new to Android and was always under the impression when calling this method I would call it as updateBook(Book book).
Below is my updateBook method
#Override
public void updateBook(Book book) {
String chapterName = editTextChapterName.getText().toString().trim();
String chapterInfo = editTextChapterInfo.getText().toString().trim();
int chapterNumber = numberPickerChapterNumber.getValue();
if (chapterName.trim().isEmpty() || chapterInfo.trim().isEmpty()) { //ensure that user has not left boxes empty
Toast.makeText(this, "Please add a chapter name and the chapter information", Toast.LENGTH_SHORT).show();
}
FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference bookRef = db.collection("Book")
.document();
bookRef.update("chapterName", book.getChapterName(),
"chapterInfo", book.getChapterInfo(),"chapterNumber", book.getChapterNumber())
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()){
Toast.makeText(AdminUpdateActivity.this, "Success", Toast.LENGTH_SHORT).show();
}
}
});
Below is where I am trying to call my method
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save_icon:
updateBook();
return true;
default:
return super.onOptionsItemSelected(item);
}
Within the updateBook parenthesis I am getting an error "Cannot be applied to ()".
I have read through other questions on here to do with this topic but have not found a solution. Can someone explain how to fix this issue and why?
Thanks

To solve this, you should change the following line of code:
DocumentReference bookRef = db.collection("Book")
.document();
to
DocumentReference bookRef = db.collection("Book")
.document(bookId);
Without passing the id of the book to the document() method, the Firebase SDK doesn't really know which book object you want to update. Beside that, calling document() method on a DocumentReference it only generates a new random id each time.
There is also another change is also needed. Please also remove the argument from your updateBook() method. Should be:
public void updateBook() {}
Without any argument.

Related

Get Value From Realtime Firebase Inside Child

Greeting everyone, im working a project right now and need help for firebase realtime database.
My firebase Project
As you guys can see in the above picture, inside student, I have matric number, and inside matric number have block and department.
I have a barcode scanner which scan the value of department and return to get the matric number. Any solution.
Below code is my progress.
mCodeScanner.setDecodeCallback(new DecodeCallback() {
#Override
public void onDecoded(#NonNull final Result result) {
runOnUiThread(new Runnable() {
#Override
public void run() {
r = result.getText();
Query s = ref.equalTo("JTMK", "department");
name.setText(r);
}});}});
If you don't know the matric number of the student, indeed a query is required. Assuming that result.getText() returns JTMK, please use the following lines of code:
mCodeScanner.setDecodeCallback(new DecodeCallback() {
#Override
public void onDecoded(#NonNull final Result result) {
String department = result.getText();
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference studentRef = db.child("Student");
Query queryByDepartment = studentRef.orderByChild("department").equalTo(department).limitToFirst(1);
queryByDepartment.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
for (DataSnapshot ds : task.getResult().getChildren()) {
String block = ds.child("block").getValue(String.class);
name.setText(block);
Log.d("TAG", block);
}
} else {
Log.d("TAG", task.getException().getMessage()); //Never ignore potential errors!
}
}
});
}
});
Things to notice:
There is no need to use runOnUiThread when reading data from the Realtime Database.
Firebase API is asynchronous. So I recommend you read the following resource:
How to read data from Firebase Realtime Database using get()?
When you run the code, you should see in the logcat BESTARI 4, which will also be set to name TextView.

Firestore asynchronous API getting null values outside readData

this is my logcat output
I am trying to fetch data from Firestore and work on them tried this but not working
getting null value for "emergencyNumber" outside "readData()"
I have tried this solution Text but still getting null
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_emergency_contact);
Log.d("TAG","Initial");
firebaseAuth = FirebaseAuth.getInstance();
fStore = FirebaseFirestore.getInstance();
userID = firebaseAuth.getCurrentUser().getUid();
readData(new FirebaseCallBack() {
#Override
public void onCallback(String str) {
emergencyNumber = str;
//Toast.makeText(EmergencyContact.this, emergencyNumber, Toast.LENGTH_SHORT).show();
phone = (TextView) dialog.findViewById(R.id.EmergencyContactNumber) ;
//emergencyNumber = phone.getText().toString() + "Hello";
phone.setText(emergencyNumber);
Log.d("TAG",emergencyNumber+"inner read me");
}
});
Log.d("TAG",emergencyNumber+"middle");
Log.d("TAG",emergencyNumber+"end");
}
private void readData(FirebaseCallBack firebaseCallBack) {
documentReference.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot document = task.getResult();
long l = document.getLong("EmergencyContact");
emergencyNumber = "0" + Long.toString(l);
firebaseCallBack.onCallback(emergencyNumber);
//Toast.makeText(EmergencyContact.this, emergencyNumber, Toast.LENGTH_SHORT).show();
Log.d("TAG",emergencyNumber+"exit read me");
}
}
});
}
private interface FirebaseCallBack {
void onCallback(String str);
}
}
Firestore asynchronous API getting null values outside readData.
Any code that needs data from Cloud Firestore needs to be inside the "onComplete()" method, or be called from there. It doesn't really matter if you create another callback, the same rules apply. This means that you cannot use the value of "emergencyNumber" outside the "onCallback()" method. Please note that this method fires, only when "onComplete()" method fires, hence that behavior. When the following Log statement is triggered:
Log.d("TAG",emergencyNumber+"middle");
The data isn't finished loading yet, that's why you have that order of execution in your logcat.
If you are not comfortable with callbacks, then I recommend you using the modern way of dealing with asynchronous programming when getting data from Firestore, which is using LiveData and ViewModel. Here you can find an example from one of my repositories where I have used the MVVM architecture pattern with LiveData and ViewModel to authenticate users in Firebase.
If you consider at some point in time to try using Kotlin, please check below an example:
https://github.com/alexmamo/FirestoreJetpackCompose
Where I have used Kotlin Coroutine for getting data from Firestore.

How Should I fetch the document fields and use them in another map for another collection?

How should I fetch the document fields from one collection and combine them to add a new document to another collection? I have attached picture of the database how does it looks, I want to fetch the fields from the collection show and want to update it to the new collection along with some other data:
private void savePost(String mPostTitle, String mPostContent, String mlistSpinnerC) {
final DocumentReference docRef = FirebaseFirestore.getInstance().collection("users").document(mauth.getCurrentUser().getUid());
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document != null) {
String username = (String)
document.get("username");
String email= (String) document.get(email);
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
postMap.put(Constants.POSTTTITLE, mPostTitle);
postMap.put(Constants.POSTCATEGORY, mlistSpinnerC);
postMap.put(Constants.POSTCONTENT, mPostContent);
postMap.put(Constants.TIMESTAMP, (System.currentTimeMillis()/1000));
postMap.put(Constants.USER_ID,mauth.getCurrentUser().getUid());
postMap.put("username", username);
PostsRef.document().set(postMap).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Intent toHomeActivity = new Intent(AddPostActivity.this, MainActivity.class);
startActivity(toHomeActivity);
}
}
});
I am just not able to map the fields from one collection to another collection, please guide me the correct method to that.
By the time you are trying to add the username to your postMap using the following line of code:
postMap.put("username", username);
The data has not finished loading yet from the database and this is because the listener you have added to your get() call is being invoked some unknown amount of time later after your query finishes. You don't know how long it's going to take, it may take from a few hundred milliseconds to a few seconds before that data is available. The onComplete() method has an asynchronous behavior, that's why you cannot get that username in such a way.
A quick solve for this problem would be to move all that block of code related to adding data to the postMap, inside the onComplete() method. In this you are waiting for the callback and username your will be available. Otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.

How to fix Android Cloud Firestore document snapshot

I am checking if the user has made an appointment in the database if not add the user(add a new document which has the user details). The problem with my app is that it runs both AddUser() and AlertUser() functions:
DocumentReference docRef = firebaseFirestore.collection(group).document(userIdentity);
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot documentSnapshot = task.getResult();
if (documentSnapshot != null) {
if (!documentSnapshot.exists()){
//User does not exist create the new user
addUser();
} else {
//User has already made an appointment show dialog
AlertUser();
}
}
}else {
Log.i("Key","Task not successfull");
}
}
});
What does this code do is checking whether a document with the userIdentity id actually exists. If it doesn't exist, the addUser() method is called, otherwise, the AlertUser() is called. There is no way in which both parts of the if statement are evaluated. So it's one or the other. You can have both method calls only if you access all those lines of code twice. Meaning that the first time the user is created and the second time is alerted. To solve this, remove from your code the part where you are calling the above code twice.
This is a Cloud Firestore question and not a Firebase Realtime database one, so I've changed the tag accordingly.

Android Cloud Firestore: Query to find a users name

I've looked for multiple solutions here but couldn't find anything specific to my situation and therefore am posting a question here while I still continue looking for a solution. I'm fairly new to Firestore still and their guide/docs are still unclear.
My phone application has a system to get a user to enter in a name. This name is to be used to traverse the Firestore database and if the name exists as a field for one of the users, then the method must return a boolean of true.
This query is to be triggered by a "continue button" which is in my main activity as shown below:
//Authenticate user and proceed to next activity
continueBtn = (Button) findViewById(R.id.continue_btn);
continueBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//On click create a db reference and perform a query on it to find current user
//and authenticate it.
CollectionReference myRef = database.collection("users");
Query findNameQ = myRef.whereEqualTo("name", mUserName);
authenticateUser(findNameQ, mUserName);//I need to pass to this method a variable 'findNameQ' which can be used to validate the existence of a user.
//mUserName is the name it's looking for.
}
});
Once the query is run then it runs the authenticateUser method which basically validates the existence of the user and creates a new one if the user doesn't exist. Here's the method:
private void authenticateUser(Query findNameQ, String mUserName)
{
//Read from database and check if user exists
//if current users name matches to one in database then set userExists to true.
if (findNameQ != null)
{
userExists = true;
Toast.makeText(this, "User exists!", Toast.LENGTH_SHORT).show();
}
Toast.makeText(this, "User doesn't exist!", Toast.LENGTH_SHORT).show();
}
I'd like to use if (findNameQ != false) instead of null, how do I make it so my findNameQ variable is a boolean and not a query object?
In order to know if a user name exists in Firestore database, you need to use a get() call. Just creating a Query object will not provide you much. Beside that, if you are checking findNameQ != null it will always evaluate to true because findNameQ object is created and will never be null. So to solve this, please use the following lines of code:
productsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
if (document.exists()) {
authenticateUser(findNameQ, mUserName);
}
}
}
}
});
Please also note, that using a addSnapshotListener will not help you because it will attach a listener to get data in real time but this is not what you need. You need to get the data only once.
You can use a boolean variable as
boolean nameFound = false;
Now, attach a snapshot listener to your query to check whether the name exists or not:
findNameQ.addSnapshotListener(new EventListener<QuerySnapshot>(){
#Override
public void onEvent(QuerySnapshot queryDocumentSnapshots, FirebaseFirestoreException e) {
for (DocumentSnapshot ds: queryDocumentSnapshots){
if (ds!=null && ds.exists()){
Toast.makeText(RegisterActivity.this, "Username Exists!", Toast.LENGTH_SHORT).show();
nameFound = true;
}
}
}
});
else the default value of nameFound that is false will be used. Now, use can use if else to call your authentication method based on the value of nameFound.

Categories

Resources