So here's my scenario:
I have three separate calls to firestore in their own classes. All three of the calls are nested within each other's callback and in the last callback I do all my work. When I trigger this stack, my Admin object will have already existed while my users list and books list would be created as this stack listens for an update. If data doesn't exist in the database and we create an entry the callback doesn't report a book (I do get Admin and User objects however). However, if we re-open the app and data already exists in the database then the callback reports something. After this, anytime I add a user/book then the list updates properly.
Note: these are realTime listeners so as soon as a user/book is added then we should see the update.
Here are my classes:
public class FirebaseGetThisAdmin {
//firebase objects
private FirebaseAuth mAuth;
private FirebaseFirestore mDbase;
private Activity activity;
private Admin admin;
private String adminID;
//default constructor
public FirebaseGetThisAdmin() {
}
public FirebaseGetThisAdmin(Activity activity) {
this.activity = activity;
}
public interface FirestoreCallback {
void onCallback(Admin admin);
}
public void readDataRTUpdate(final FirestoreCallback firestoreCallback) {
//firebase new instances
mAuth = FirebaseAuth.getInstance();
mDbase = FirebaseFirestore.getInstance();
//get admin email address and user name from Auth and set textInput fields to them
if (mAuth.getCurrentUser() != null) {
adminID = mAuth.getUid();
}
final DocumentReference docRef = mDbase.collection("admins").document(adminID);
docRef.addSnapshotListener(activity, new EventListener<DocumentSnapshot>() {
#Override
public void onEvent(#Nullable DocumentSnapshot snapshot,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "Listen failed.", e);
return;
}
String source = snapshot != null && snapshot.getMetadata().hasPendingWrites()
? "Local" : "Server";
if (snapshot != null && snapshot.exists()) {
admin = new Admin();
admin = snapshot.toObject(Admin.class);
//pass variables to the callback
firestoreCallback.onCallback(admin);
Log.d(TAG, source + " data: " + snapshot.getData());
} else {
Log.d(TAG, source + " data: null");
}
}
});
}
}
public class FirebaseGetUsers {
//firebase objects
private FirebaseAuth mAuth;
private FirebaseFirestore mDbase;
private Activity activity;
private String adminID;
//default constructor
public FirebaseGetUsers() {
}
public FirebaseGetUsers(Activity activity) {
this.activity = activity;
//firebase new instances
mAuth = FirebaseAuth.getInstance();
mDbase = FirebaseFirestore.getInstance();
if (mAuth.getCurrentUser() != null) {
adminID = mAuth.getUid();
}
}
public interface FirestoreCallback {
void onCallback(List<User> users);
}
public void readDataRTUpdate(final FirestoreCallback firestoreCallback) {
mDbase.collection("admins").document(adminID).collection("users")
.addSnapshotListener(activity, new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "Listen failed.", e);
return;
}
if (value != null) {
int i = 0;
List<User> users = new ArrayList<>();
for (QueryDocumentSnapshot document : value) {
users.add(document.toObject(User.class));
Log.d(TAG, "User: " + users.get(i).toString());
i++;
}
firestoreCallback.onCallback(users);
Log.d(TAG, "Document updated.");
}
else {
Log.d(TAG, "No such document");
}
}
});
}
}
Next:
public class FirebaseGetUsers {
//firebase objects
private FirebaseAuth mAuth;
private FirebaseFirestore mDbase;
private Activity activity;
private String adminID;
//default constructor
public FirebaseGetUsers() {
}
public FirebaseGetUsers(Activity activity) {
this.activity = activity;
//firebase new instances
mAuth = FirebaseAuth.getInstance();
mDbase = FirebaseFirestore.getInstance();
if (mAuth.getCurrentUser() != null) {
adminID = mAuth.getUid();
}
}
public interface FirestoreCallback {
void onCallback(List<User> users);
}
public void readDataRTUpdate(final FirestoreCallback firestoreCallback) {
mDbase.collection("admins").document(adminID).collection("users")
.addSnapshotListener(activity, new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "Listen failed.", e);
return;
}
if (value != null) {
int i = 0;
List<User> users = new ArrayList<>();
for (QueryDocumentSnapshot document : value) {
users.add(document.toObject(User.class));
Log.d(TAG, "User: " + users.get(i).toString());
i++;
}
firestoreCallback.onCallback(users);
Log.d(TAG, "Document updated.");
}
else {
Log.d(TAG, "No such document");
}
}
});
}
}
Next:
public class FirebaseGetBooks {
//firebase objects
private FirebaseFirestore mDbase;
private Activity activity;
private String groupID;
//default constructor
public FirebaseGetBooks() {
}
public FirebaseGetBooks(Activity activity) {
this.activity = activity;
//firebase new instances
mDbase = FirebaseFirestore.getInstance();
FirebaseGetGroupID firebaseGetGroupID = new FirebaseGetGroupID(activity);
groupID = firebaseGetGroupID.getGroupID();
}
public interface FirestoreCallback {
void onCallback(List<Book> books);
}
public void readDataRTUpdate(final FirestoreCallback firestoreCallback) {
mDbase.collection("books").whereEqualTo("groupID", groupID)
.addSnapshotListener(activity, new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "Listen failed.", e);
return;
}
if (value != null) {
int i = 0;
List<Book> books = new ArrayList<>();
for (QueryDocumentSnapshot document : value) {
books.add(document.toObject(Book.class));
Log.d(TAG, "Book: " + books.get(i).toString());
i++;
}
firestoreCallback.onCallback(books);
Log.d(TAG, "Document updated.");
}
else {
Log.d(TAG, "No such document");
}
}
});
}
}
And finally my call in MainActivity:
firebaseGetUsers.readDataRTUpdate(new FirebaseGetUsers.FirestoreCallback() {
#Override
public void onCallback(final List<User> users) {
firebaseGetBooks.readDataRTUpdate(new FirebaseGetBooks.FirestoreCallback() {
#Override
public void onCallback(final List<Book> books) {
firebaseGetThisAdmin.readDataRTUpdate(new FirebaseGetThisAdmin.FirestoreCallback() {
#Override
public void onCallback(Admin admin) {
//processing all code here.
//books are empty!!
System.out.println("books: " + books.toString());
}
}
});
}
});
}
});
I can't figure out what I'm doing wrong...any ideas would be greatly appreciated.
Thanks!
Okay, so I was able to finally solve this issue. It had nothing to do with the Firestore nested callbacks. If you notice in the getBooks class, I'm referencing a groupID value. This value represents this Admin's account (holds reference to both users and other admins). Since this value never changes throughout the life of the account, I'm storing it locally in shared preferences so I can reduce database get() commands. However, it appears that on first login, the variable groupID isn't getting set quickly enough before we try to use it to access books from the database.
So, the net result is that books isn't able to find any documents since the variable isn't set yet.
My fix for this is two-folded. When the admin creates their account, the groupID is created when we create our first document reference. At this point we store it immediately to sharedPrefs. No need to try to get it from the database at this point, since it created and accessible locally. Second, I nested the Firestore get() groupID callback inside of our Firestore sign in method. So anything that gets executed when the user logs in happens AFTER we retrieve this value (for proper cleanup purposes the groupID is cleared from sharedPrefs on every logout).
Related
I apply (Callback method to fix the asynchronous problem)the https://www.youtube.com/watch?v=0ofkvm97i0s video. But I have problems.
Hear are readData and interface.
private void readData(FirestoreCallback firestorecallback){
String currentUserId = firebaseAuth.getCurrentUser().getUid();
DocumentReference docRef = firestore.collection("Users").document(currentUserId);
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if(task.isSuccessful()){
DocumentSnapshot document = task.getResult();
if(document.exists()){
a = document.getString('gender');
}
firestorecallback.onCallback(a);
}
}
});
}
private interface FirestoreCallback{
void onCallback(String b);
}
And in onCreate method
readData(new FirestoreCallback() {
#Override
public void onCallback(String b) {
String c;
if(b=='남자'){
c ='여자';
}
if(b=='여자'){
c = '남자';
}
EventChangeListener(b);
Log.d('',b);
Log.d('',c);
}
});
EventChangeListener function's code
private void EventChangeListener(String a) {
//firestore.collection('Users').orderBy('time',Query.Direction.DESCENDING).limit(50)
//
firestore.collection('Users')
//.whereEqualTo('mbti','ENTP')
//.whereEqualTo('region','')
.whereEqualTo('gender',a)
.orderBy('time',Query.Direction.DESCENDING).limit(50)
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException error) {
if(error != null){
if(progressDialog.isShowing()){
progressDialog.dismiss();
}
Log.e("Firestore error",error.getMessage());
return;
}
for (DocumentChange dc : value.getDocumentChanges()){
if (dc.getType() == DocumentChange.Type.ADDED){
userArrayList.add(dc.getDocument().toObject(User.class));
}
myAdapter.notifyDataSetChanged();
if(progressDialog.isShowing()){
progressDialog.dismiss();
}
}
}
});
}
As you can see, I can get the variable 'b' but I want to when users' 'b' is male c-> male, 'b' is female c-> male.
So I define the variable 'c' but android said variable c is not defined
public void onCallback(String b) {
String c;
if(b=='female'){
c ='male';
}
if(b=='male'){
c = 'female';
}
EventChangeListener(b);
Log.d('',b);
Log.d('',c);
}
So the app crashes when the user presses the sign-in button and only if the details he wrote down in the edit texts are correct by the firebaseAuth. reopening the app will make the app behave as nothing happened and the user will be signed in.
Here's the code:
public class LoginActivity extends Activity {
private Button btnRegister, btnSignIn, btnForgot;
private EditText etPhone, etPassword;
private ProgressBar mprogressBar;
private FirebaseAuth fbAuth;
private FirebaseUser fbUser;
private FirebaseFirestore db;
private DocumentReference uDocRef;
private CollectionReference uColctRef;
SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
btnRegister = findViewById(R.id.btnRegister);
btnSignIn = findViewById(R.id.btnSignIn);
btnForgot = findViewById(R.id.btnForgot);
etPhone = findViewById(R.id.etPhone);
etPassword = findViewById(R.id.etPassword);
mprogressBar = findViewById(R.id.mprogressBar);
fbAuth = FirebaseAuth.getInstance();
fbUser = fbAuth.getCurrentUser();
initFirebase();
}
private void initFirebase() {
db = FirebaseFirestore.getInstance();
uColctRef = db.collection(UserFirebase.UsersCollection);
if (fbUser != null)
{
Toast.makeText(this, "User already logged in: " + fbUser.getEmail(), Toast.LENGTH_LONG).show();
refreshListAndSubscribe();
Intent zone = new Intent(this, ZoneActivity.class);
startActivity(zone);
}
}
private void refreshListAndSubscribe() {
uColctRef
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot result,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.e("FirebaseDemo-Query", "Listen failed", e);
e.printStackTrace();
return;
}
Log.i("FirebaseDemo-Query", "Listen succeded");
checklist(result);
}
});
}
private void checklist(QuerySnapshot result) {
String email;
boolean isApproved;
sharedPreferences = getSharedPreferences("SaveData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
for (QueryDocumentSnapshot document : result) {
email = document.get(UserFirebase.email).toString();
if (etPhone.getText().toString().trim().equals(email))
{
String branchCode = String.valueOf(document.get(UserFirebase.branchCode));
String role = document.get(UserFirebase.roleType).toString();
isApproved = Boolean.parseBoolean(document.get(UserFirebase.isApproved).toString());
editor.putString("myBranch", branchCode);
editor.putString("myRole", role);
editor.putString("myEmail", email);
editor.putBoolean("isApproved", isApproved);
editor.apply();
}
if (fbUser != null)
{
if (fbUser.getEmail().equals(email))
{
String branchCode = String.valueOf(document.get(UserFirebase.branchCode));
String role = document.get(UserFirebase.roleType).toString();
isApproved = Boolean.parseBoolean(document.get(UserFirebase.isApproved).toString());
editor.putString("myBranch", branchCode);
editor.putString("myRole", role);
editor.putString("myEmail", email);
editor.putBoolean("isApproved", isApproved);
editor.apply();
}
}
}
}
public void onSign(View v)
{
if (isEmpty())
return;
inProgress(true);
fbAuth.signInWithEmailAndPassword(etPhone.getText().toString().trim(), etPassword.getText().toString())
.addOnSuccessListener(new OnSuccessLstnr("User Signed In", true))
.addOnFailureListener(new OnFailLstnr("Sign-in failed!"));
}
public void setPassword(View v)
{
Intent pass = new Intent(this, PasswordActivity.class);
startActivity(pass);
}
public void onRegister(View v)
{
Intent auth = new Intent (this, RegisterActivity.class);
startActivity(auth);
}
private void inProgress(boolean inProgress)
{
if (inProgress)
{
mprogressBar.setVisibility(View.VISIBLE);
btnSignIn.setEnabled(false);
btnRegister.setEnabled(false);
btnForgot.setEnabled(false);
}
else
{
mprogressBar.setVisibility(View.INVISIBLE);
btnSignIn.setEnabled(true);
btnRegister.setEnabled(true);
btnForgot.setEnabled(true);
}
}
private boolean isEmpty()
{
if (TextUtils.isEmpty(etPhone.getText().toString()))
{
etPhone.setError("REQUIRED!");
return true;
}
if (TextUtils.isEmpty(etPassword.getText().toString()))
{
etPassword.setError("REQUIRED!");
return true;
}
return false;
}
private class OnFailLstnr implements OnFailureListener
{
String msg;
public OnFailLstnr(String _msg)
{
this.msg = _msg;
}
#Override
public void onFailure(#NonNull Exception e)
{
inProgress(false);
Toast.makeText(LoginActivity.this, msg, Toast.LENGTH_SHORT).show();
}
}
public class OnSuccessLstnr implements OnSuccessListener<AuthResult>
{
String msg;
boolean open;
OnSuccessLstnr(String _msg, boolean _open)
{
this.msg = _msg;
this.open = _open;
}
#Override
public void onSuccess(AuthResult authResult)
{
Toast.makeText(LoginActivity.this, msg, Toast.LENGTH_LONG).show();
inProgress(false);
if (open)
{
refreshListAndSubscribe();
Intent in = new Intent(LoginActivity.this, ZoneActivity.class);
startActivity(in);
finish();
}
}
}
The Logcat:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.firebase.auth.FirebaseUser.getEmail()' on a null object reference
at com.a.shon.scoutszone2.Activities.LoginActivity.checklist(LoginActivity.java:127)
at com.a.shon.scoutszone2.Activities.LoginActivity.access$000(LoginActivity.java:42)
at com.a.shon.scoutszone2.Activities.LoginActivity$1.onEvent(LoginActivity.java:101)
at com.a.shon.scoutszone2.Activities.LoginActivity$1.onEvent(LoginActivity.java:91)
I've Tried fixing it using answers to some similliar questions that were already posted in the site, but it didn't really change or fix the problem.
I would like to get help with solving this issue out and every help would be appreciated by A LOT!
Thanks in advance!
Found a solution, Seems like dealing with Already authenticated users (Users who already logged in, just reopening the app) and users who are just logged out from the app in one method (Check the - private void checklist(QuerySnapshot result), to understand what I'm talking about) is quite a messy way to deal with it, and making it really buggy.
The solution:
In InitFirebase() change the calling of refreshListAndSubscribe(); to a different new method, i called it refreshExistingUser(), its the same code as refreshListAndSubscribe()
the only part which is different between the two is the calling for the second method at the end of them.
Ill Add here a part of the code to make it simpler to understand:
private void initFirebase() {
db = FirebaseFirestore.getInstance();
uColctRef = db.collection(UserFirebase.UsersCollection);
if (fbUser != null)
{
Toast.makeText(this, "User already logged in: " + fbUser.getEmail(), Toast.LENGTH_LONG).show();
refreshExistingUser();
Intent zone = new Intent(this, ZoneActivity.class);
startActivity(zone);
}
}
private void refreshListAndSubscribe() {
uColctRef
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot result,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.e("FirebaseDemo-Query", "Listen failed", e);
e.printStackTrace();
return;
}
Log.i("FirebaseDemo-Query", "Listen succeded");
checklist(result);
}
});
}
private void checklist(QuerySnapshot result) {
String email;
boolean isApproved;
sharedPreferences = getSharedPreferences("SaveData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
for (QueryDocumentSnapshot document : result) {
email = document.get(UserFirebase.email).toString();
if (etPhone.getText().toString().trim().equals(email))
{
String branchCode = String.valueOf(document.get(UserFirebase.branchCode));
String role = document.get(UserFirebase.roleType).toString();
isApproved = Boolean.parseBoolean(document.get(UserFirebase.isApproved).toString());
editor.putString("myBranch", branchCode);
editor.putString("myRole", role);
editor.putString("myEmail", email);
editor.putBoolean("isApproved", isApproved);
editor.apply();
}
}
}
private void refreshExistingUser() {
uColctRef
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot result,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.e("FirebaseDemo-Query", "Listen failed", e);
e.printStackTrace();
return;
}
Log.i("FirebaseDemo-Query", "Listen succeded");
checkuser(result);
}
});
}
private void checkuser(QuerySnapshot result) {
String email;
boolean isApproved;
sharedPreferences = getSharedPreferences("SaveData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
for (QueryDocumentSnapshot document : result) {
email = document.get(UserFirebase.email).toString();
if (fbUser.getEmail().equals(email)) { //When the user isnt == null (Reopening the app and such)
String branchCode = String.valueOf(document.get(UserFirebase.branchCode));
String role = document.get(UserFirebase.roleType).toString();
isApproved = Boolean.parseBoolean(document.get(UserFirebase.isApproved).toString());
editor.putString("myBranch", branchCode);
editor.putString("myRole", role);
editor.putString("myEmail", email);
editor.putBoolean("isApproved", isApproved);
editor.apply();
}
}
}
When I get data from Cloud Firestore in android. It returns an empty variable. It should return the value of the flag true or false.
public boolean checkIfUserAlreadyExists(final String email) {
final boolean[] flag = {false};
db.collection(context.getString(R.string.db_collection_users))
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
if (document.getData().get(context.getString(R.string.db_field_email)).toString() != null && document.getData().get(context.getString(R.string.db_field_email)).toString().equals(email)) {
Toast.makeText(context, "User Already exits", Toast.LENGTH_SHORT);
Log.e(TAG, "User already exists" + document.getData().get("email").toString());
flag[0] = true;
} else {
Log.e(TAG, "User do not exists");
}
}
} else {
Log.e(TAG, "Error getting documents.", task.getException());
}
}
});
return flag[0];
}
flag[0] should return true but it returns false when called in another activity.
addOnCompleteListener works asynchronously.
That is you are returning flag[0] immeadiately after the OnCompleteListener is set. By that time the onComplete() would not have called and hence the flag[0] still have the initial value. This compiler expected this type of error that's why it's warned you that you can not change non final variables inside the callback method. But you bypassed it in a strange way by making it an array 😀
You have can solve this in multiple ways
Solution 1
Instead of returning the value, access the value from the callback
public void checkIfUserAlreadyExists(final String email) {
db.collection(context.getString(R.string.db_collection_users))
.get()
.addOnCompleteListener(new OnCompleteListener < QuerySnapshot > () {
#Override
public void onComplete(#NonNull Task < QuerySnapshot > task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document: task.getResult()) {
if (document.getData().get(context.getString(R.string.db_field_email)).toString() != null && document.getData().get(context.getString(R.string.db_field_email)).toString().equals(email)) {
Toast.makeText(context, "User Already exits", Toast.LENGTH_SHORT);
Log.e(TAG, "User already exists" + document.getData().get("email").toString());
// User exists.
userTheResult(true);
return;
} else {
Log.e(TAG, "User do not exists");
}
}
// No user exists.
userTheResult(false);
} else {
Log.e(TAG, "Error getting documents.", task.getException());
}
}
});
}
Solution 2
You can use this class to make a thread waiting until the result is obtained. This way you don't have to change your code much. What you have to do is simply add the class ThreadLockedTask<T> as it is to your project and use it as in the example given.
import java.util.concurrent.atomic.AtomicReference;
/**
* #author Ahamad Anees P.A
* #version 1.0
* #param <T> type
*/
public class ThreadLockedTask<T> {
private AtomicReference<ResultWrapper<T>> mReference;
public ThreadLockedTask() {
mReference = new AtomicReference<>(new ResultWrapper<T>());
}
public T execute(Runnable runnable) {
runnable.run();
if (!mReference.get().mIsSet)
lockUntilSet();
return mReference.get().mResult;
}
private void lockUntilSet() {
synchronized (this) {
while (!mReference.get().isSet()) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
public void setResult(T result) {
synchronized (this) {
ResultWrapper<T> wrapper = mReference.get();
wrapper.setResult(result);
wrapper.setIsSet(true);
notify();
}
}
public static class ResultWrapper<T> {
private boolean mIsSet;
private T mResult;
public boolean isSet() {
return mIsSet;
}
public T getResult() {
return mResult;
}
void setIsSet(boolean isCompleted) {
this.mIsSet = isCompleted;
}
void setResult(T result) {
this.mResult = result;
}
}
}
Usage
public boolean checkIfUserAlreadyExists(final String email) {
ThreadLockedTask < Boolean > task = new ThreadLockedTask < > ();
boolean flag = task.execute(new Runnable() {
#Override
public void run() {
db.collection(context.getString(R.string.db_collection_users))
.get()
.addOnCompleteListener(new OnCompleteListener < QuerySnapshot > () {
#Override
public void onComplete(#NonNull Task < QuerySnapshot > task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document: task.getResult()) {
if (document.getData().get(context.getString(R.string.db_field_email)).toString() != null && document.getData().get(context.getString(R.string.db_field_email)).toString().equals(email)) {
Toast.makeText(context, "User Already exits", Toast.LENGTH_SHORT);
Log.e(TAG, "User already exists" + document.getData().get("email").toString());
task.setResult(true);
return;
} else {
Log.e(TAG, "User do not exists");
}
}
} else {
Log.e(TAG, "Error getting documents.", task.getException());
}
task.setResult(false);
}
});
}
});
return flag;
}
I'm having an issue with FireStore offline persistence when getting information from a single document.
The below method of filling form works fine when online, but I'm seeing a long delay (filling data into a simple EditText form) when I test the app offline (sometimes three or four seconds):
private void importFirestoreData() {
dbDocument = dbFirestore.collection("sites").document(siteId);
dbDocument.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d(TAG, "DocumentSnapshot data: " + document.getData());
companyNameEditText.setText(document.getString("companyName"));
siteLocationEditText.setText(document.getString("siteLocation"));
siteAddressEditText.setText(document.getString("siteAddress"));
companyWebsiteEditText.setText(document.getString("companyWebsite"));
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
}
The rest of the code is here:
public class SiteAddEditActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "SiteAddEditActivity";
public static final String KEY_SITE_ID = "key_site_id";
private TextView mainTitleTextView;
private EditText companyNameEditText, siteLocationEditText, siteAddressEditText, companyWebsiteEditText;
private Button saveButton, cancelButton;
private String siteId;
// Database declarations
private FirebaseAuth mAuth;
private FirebaseUser mUser;
private FirebaseFirestore dbFirestore;
private DocumentReference dbDocument;
private Query dbQuery;
private boolean newDoc;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
setContentView(R.layout.site_add_edit_activity);
setUpViews();
setUpListeners();
setUpFirestore();
getIDfromExtras();
}
private void setUpViews() {
mainTitleTextView = findViewById(R.id.textViewMainHeading);
companyNameEditText = findViewById(R.id.editTextCompanyName);
siteLocationEditText = findViewById(R.id.editTextSiteLocation);
siteAddressEditText = findViewById(R.id.editTextSiteAddress);
companyWebsiteEditText = findViewById(R.id.editTextCompanyWebsite);
saveButton = findViewById(R.id.buttonSave);
cancelButton = findViewById(R.id.buttonCancel);
}
private void setUpListeners() {
saveButton.setOnClickListener(this);
cancelButton.setOnClickListener(this);
}
private void setUpFirestore() {
mAuth = FirebaseAuth.getInstance();
mUser = mAuth.getCurrentUser();
dbFirestore = FirebaseFirestore.getInstance();
}
private void getIDfromExtras() {
newDoc = true;
// Get site ID from extras
siteId = getIntent().getExtras().getString(KEY_SITE_ID);
if (siteId == null) {
throw new IllegalArgumentException("Must pass extra " + KEY_SITE_ID);
}
else {
newDoc = false;
mainTitleTextView.setText(R.string.app_edit_site);
importFirestoreData();
}
}
private void importFirestoreData() {
dbDocument = dbFirestore.collection("sites").document(siteId);
dbDocument.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d(TAG, "DocumentSnapshot data: " + document.getData());
companyNameEditText.setText(document.getString("companyName"));
siteLocationEditText.setText(document.getString("siteLocation"));
siteAddressEditText.setText(document.getString("siteAddress"));
companyWebsiteEditText.setText(document.getString("companyWebsite"));
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
}
#Override
public void onClick(View view) {
int i = view.getId();
if(i == R.id.buttonSave){
if (newDoc){
saveSite();
}
else {
updateSite();
}
startActivity(new Intent(SiteAddEditActivity.this, SiteActivity.class));
} else if (i == R.id.buttonCancel) {
FirebaseAuth mAuth = FirebaseAuth.getInstance();
Toast.makeText(this, "User (" + mAuth.getUid() + ") Signed Out!", Toast.LENGTH_LONG).show();
mAuth.signOut();
startActivity(new Intent(SiteAddEditActivity.this,LoginMainActivity.class));
}
}
private void updateSite() {
SitePOJO updateSite = new SitePOJO(
companyNameEditText.getText().toString().trim(),
siteLocationEditText.getText().toString().trim(),
siteAddressEditText.getText().toString(),
companyWebsiteEditText.getText().toString().trim()
);
dbDocument.set(updateSite);
}
private void saveSite() {
SitePOJO newSite = new SitePOJO(
companyNameEditText.getText().toString().trim(),
siteLocationEditText.getText().toString().trim(),
siteAddressEditText.getText().toString(),
companyWebsiteEditText.getText().toString().trim()
);
dbDocument = dbFirestore.collection("sites").document();
String thisDoc = dbDocument.getId();
dbDocument.set(newSite);
Toast.makeText(this, "New site created (document ref: " + thisDoc + ")", Toast.LENGTH_LONG).show();
}
}
I'm guessing it is how I am getting the data - I'm wondering if it is better to handle the data in some sort of adapter (separate to the activities?)..
Thank you to Reaz - yes this post did help..
My simple mind got confused between.get().addOnCompleteListener and .addSnapshotListener..
Correct working code below:
private void importFirestoreData() {
dbDocument = dbFirestore.collection("sites").document(siteId);
dbDocument.addSnapshotListener(new EventListener<DocumentSnapshot>() {
#Override
public void onEvent(#javax.annotation.Nullable DocumentSnapshot documentSnapshot, #javax.annotation.Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "Listen failed.", e);
return;
}
if (documentSnapshot != null && documentSnapshot.exists()) {
Log.d(TAG, "Current data: " + documentSnapshot.getData());
companyNameEditText.setText(documentSnapshot.getString("companyName"));
siteLocationEditText.setText(documentSnapshot.getString("siteLocation"));
siteAddressEditText.setText(documentSnapshot.getString("siteAddress"));
companyWebsiteEditText.setText(documentSnapshot.getString("companyWebsite"));
} else {
Log.d(TAG, "Current data: null");
}
}
});
}
I want to read the a value from firestore document. But it doesn't work for me and I don't know where is the problem.should i use get() or realtime updates.
I tried both but doesn't work for me
this is my code.
I confirmed my positions by using toast and the are ok.
How to solve this problem?
public class SingleAdActivity extends AppCompatActivity {
String x;
String a;
String z;
String coname;
TextView Co_Name;
private ListenerRegistration listenerRegistration;
DocumentReference firebaseFirestore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_ad);
Co_Name = findViewById(R.id.SingleAd_CoName);
ad_discription = findViewById(R.id.disrcibe_ad);
phone_number = findViewById(R.id.phone);
x = getIntent().getStringExtra("single_ad_position");
a = getIntent().getStringExtra("single_ad_categoryP");
z = getIntent().getStringExtra("documentId");
firebaseFirestore = FirebaseFirestore.getInstance().collection("MainCategories")
.document(String.valueOf(a))
.collection("Ads")
.document(z);
#Override
protected void onStart () {
super.onStart();
listenerRegistration = firebaseFirestore
.addSnapshotListener(this, new EventListener<DocumentSnapshot>() {
#Override
public void
onEvent(#Nullable DocumentSnapshot documentSnapshot, #Nullable FirebaseFirestoreException e) {
if (e != null) {
Toast.makeText(SingleAdActivity.this, "error", Toast.LENGTH_SHORT).show();
return;
}
assert documentSnapshot != null;
if (documentSnapshot.exists()) {
coname = documentSnapshot.getString("CompanyName");
Co_Name.setText(coname);
} else {
// Co_Name.setText(a);
}
}
});
}
#Override
protected void onStop () {
super.onStop();
listenerRegistration.remove();
}
}
}
The way I do it is like this:
FirebaseFirestore firestoreDb = FirebaseFirestore.getInstance();
firestoreDb..collection(yourCollection)
.document(yourDocument)
.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if(task.isSuccessful()) {
Object yourObject = task.getResult().toObject(YourClassName.class);
} else {
if(task.getException() != null)
{
task.getException().printStackTrace();
}
}
}
});