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");
}
}
});
}
Related
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();
}
}
}
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();
}
}
}
});
I am using Cloud Firestore as my database to save all users as documents in 'users' collection. I want to display all the users in 'users' collection into my RecyclerView except the current user who is currently using the app. I searched a lot to find a solution all over the internet but could not find any. So please help me out guys and thanks in advance. I'm a beginner, so really need your help. And thanks again.
This is my Firestore adapter:
mQuery = FirebaseFirestore.getInstance().collection("users");
FirestoreRecyclerOptions<NearbyUserRecyclerModel> options = new FirestoreRecyclerOptions.Builder<NearbyUserRecyclerModel>()
.setQuery(mQuery,NearbyUserRecyclerModel.class)
.setLifecycleOwner(getActivity())
.build();
FirestoreRecyclerAdapter adapter = new FirestoreRecyclerAdapter<NearbyUserRecyclerModel,NearbyProfilesViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final NearbyProfilesViewHolder holder, int position, #NonNull final NearbyUserRecyclerModel model) {
holder.itemBuddyState.setText("0");
Glide.with(getActivity()).load(model.getThumb_pictures()).into(holder.itemImage);
holder.itemDisplayName.setText(model.getFirst_name());
holder.itemOnline.setVisibility(View.VISIBLE);
DocumentSnapshot snapshot = getSnapshots().getSnapshot(position);
if (snapshot.contains("online")){
Boolean onlineState = snapshot.getBoolean("online");
if (onlineState == true){
holder.itemOnline.setVisibility(View.VISIBLE);
}
else {
holder.itemOnline.setVisibility(View.INVISIBLE);
}
}
final String user_id = snapshot.getId();
mChatRequestCollection.document(current_user_id).collection("request_received")
.document(user_id).get().addOnCompleteListener(getActivity(),
new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot document = task.getResult();
if (document.contains("received_time")){
holder.itemBuddyState.setText("3");
}else {
Log.d("REQUEST RECEIVED", "onComplete: received field doest exist, "+task.getException());
}
}else {
Log.d("REQUEST RECEIVED", "onComplete: Document doesn't exist, "+ task.getException());
}
}
});
mChatRequestCollection.document(current_user_id).collection("request_sent")
.document(user_id).get().addOnCompleteListener(getActivity(),
new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot document = task.getResult();
if (document.contains("sent_time")){
holder.itemBuddyState.setText("2");
}else {
Log.d("REQUEST SENT", "onComplete: sent field doesn't exist, "+ task.getException());
}
}else {
Log.d("REQUEST SENT", "onComplete: Document doesn't exist,");
}
}
});
mChatHolderCollection.document(current_user_id+"/user_chats/"+user_id)
.get().addOnCompleteListener(getActivity(),
new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot document = task.getResult();
if (document.contains("timestamp")){
holder.itemBuddyState.setText("1");
}else {
Log.d("CHAT_HOLDERDOC", "onComplete: timeStamp field doesn't exist, "+task.getException());
}
}else {
Log.d("CHAT_HOLDERDOC", "onComplete: chat buddy doesn't exist, "+task.getException());
}
}
});
holder.itemImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
userPopupDialog(model, user_id);
// popupIntent(user_id);
}
});
holder.itemButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
String message = holder.itemEditText.getText().toString();
if (holder.itemBuddyState.getText().equals("0")){
if (!TextUtils.isEmpty(message)) {
WriteBatch request_batch = mRootStore.batch();
Map<String, Object> sentMap = new HashMap<>();
sentMap.put("sent_time", FieldValue.serverTimestamp());
sentMap.put("message", message);
Map<String, Object> receivedMap = new HashMap<>();
receivedMap.put("received_time", FieldValue.serverTimestamp());
receivedMap.put("message", message);
Map<String, Object> notificationMap = new HashMap<>();
notificationMap.put("from", current_user_id);
notificationMap.put("type", "request");
DocumentReference sentRef = mRootStore.collection("chat_requests").document(current_user_id + "/request_sent/" + user_id);
request_batch.set(sentRef, sentMap, SetOptions.merge());
DocumentReference receivedRef = mRootStore.collection("chat_requests").document(user_id + "/request_received/" + current_user_id);
request_batch.set(receivedRef, receivedMap, SetOptions.merge());
DocumentReference notificationRef = mRootStore.collection("users/" + user_id + "/notifications").document();
request_batch.set(notificationRef, notificationMap, SetOptions.merge());
request_batch.commit().addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
//------------Request Sent------------//
holder.itemEditText.setText("");
holder.itemBuddyState.setText("2");
Log.d("REQUEST_LOG", "onComplete: Request sent Successfully");
Log.d("REQUEST_LOG", "onComplete: Notification sent Successfully");
Snackbar.make(v, "Request sent Successfully", Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(v, "Failed Sending Request", Snackbar.LENGTH_LONG).show();
Log.d("REQUEST_LOG", "onComplete: Failed sending request" + task.getException());
}
}
});
}
}
if (holder.itemBuddyState.getText().equals("3")){
holder.itemEditText.setText("");
Snackbar.make(v, "Request already received by user", Snackbar.LENGTH_LONG).show();
}
if (holder.itemBuddyState.getText().equals("2")){
holder.itemEditText.setText("");
Snackbar.make(v, "Request already sent", Snackbar.LENGTH_LONG).show();
}
if (holder.itemBuddyState.getText().equals("1")){
holder.itemEditText.setText("");
Snackbar.make(v,"User already chat buddy", Snackbar.LENGTH_LONG).show();
}
}
});
}
#NonNull
#Override
public NearbyProfilesViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.nearby_profiles_recycler_items, parent, false);
final AppCompatImageButton button_send = view.findViewById(R.id.itemSendButton_id);
final AppCompatEditText editText_message = view.findViewById(R.id.itemEditText_id);
Drawable drawable = getResources().getDrawable(R.drawable.ic_send_new);
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable, getResources().getColor(R.color.colorTabUnselected));
button_send.setImageDrawable(drawable);
button_send.setEnabled(false);
editText_message.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String message = editText_message.getText().toString();
if (TextUtils.isEmpty(message)){
Drawable drawable = getResources().getDrawable(R.drawable.ic_send_new);
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable, getResources().getColor(R.color.colorTabUnselected));
button_send.setImageDrawable(drawable);
button_send.setEnabled(false);
}
else {
Drawable drawable = getResources().getDrawable(R.drawable.ic_send_new);
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable, getResources().getColor(R.color.colorTabSelected));
button_send.setImageDrawable(drawable);
button_send.setEnabled(true);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
return new NearbyProfilesViewHolder(view);
}
};
nearbyRecycler.setAdapter(adapter);
Change the IF condition in the below method
public void getUserData(){
db.collection("users")
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(TAG, document.getId() + " => " + document.getData());
if(document.getData().get("userID").equals(userID)){
// User user = (User)document.getData();
// Log.e(TAG, "onComplete: "+user.getUserName()+ user.getDescription() + user.isGender());
Map<String, Object> user = new HashMap<>();
user.put("name", document.getData().get("name"));
user.put("userID", document.getData().get("userID"));
user.put("email", document.getData().get("email"));
user.put("companyName",document.getData().get("companyName"));
user.put("officeAddress", document.getData().get("officeAddress"));
user.put("phoneNumber", document.getData().get("phoneNumber"));
user.put("gender",document.getData().get("gender"));
user.put("isProfileComplete",document.getData().get("isProfileComplete"));
user.put("profilePicUrl", document.getData().get("profilePicUrl"));
user.put("description", document.getData().get("description"));
/* if(document.getData().get("isProfileComplete")){
LoginActivity loginActivity = (LoginActivity)mContext;
loginActivity.navigateToHome();
}else{
LoginActivity loginActivity = (LoginActivity)mContext;
loginActivity.navigateToHome();
}*/
boolean check = (Boolean) document.getData().get("isProfileComplete");
if(check){
LoginActivity loginActivity = (LoginActivity)mContext;
loginActivity.navigateToHome();
}else{
LoginActivity loginActivity = (LoginActivity)mContext;
loginActivity.navigateToOnBoarding();
}
Log.e(TAG, "onComplete:GET DADA "+ user.get("isProfileComplete"));
}else{
Log.e(TAG, "onComplete:ID "+document.getData().get("userID") );
LoginActivity loginActivity = (LoginActivity)mContext;
loginActivity.navigateToOnBoarding();
}
}
} else {
Log.w(TAG, "Error getting documents.", task.getException());
}
}
});
}
There is no way in which you can query a Firestore database using != (not equal to operator). So the following line of code does not exist:
Query query = db.collection("users").whereNotEqualTo("userID", userID);
In this case, you need to create your own logic for that. To solve this, you need to query your database for all users but the adapter should receive all of them except one, the current user. So you need to create an if statement to check if the current user is different than the others.
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).
This is my Service class which is calling to all listener
public class DBService extends Service {
private static final String TAG = DBService.class.getName();
private DatabaseReference reference;
private static final String FIREBASE_EMAIL = "xxxxxxx#workindia.in";
private static final String FIREBASE_PASSWORD = "xxxxxx";
#Override
public void onCreate() {
super.onCreate();
FirebaseDatabase database = FirebaseDatabase.getInstance();
reference = database.getReference();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
FirebaseAuth auth = ((StartApplication) getApplication()).getAuth();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null) {
String email = ObjectGraph.getEmployeeProfile().getEmail();
String password = ObjectGraph.getEmployeeProfile().getMobile_no();
if (password != null && !password.trim().isEmpty()) {
if (email == null || email.trim().isEmpty()) {
email = password + FIREBASE_EMAIL;
}
signIn(auth, email, FIREBASE_PASSWORD);
}
} else {
addListeners();
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
addListeners();
return null;
}
private void signIn(final FirebaseAuth auth, final String email, final String password) {
Log.i(TAG, "Login");
auth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
boolean isResetTimeStamp = true;
setTimeStamp(isResetTimeStamp);
addListeners();
} else {
register(auth, email, password);
}
}
});
FirebaseAuth.AuthStateListener authListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
Log.e(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
Log.e(TAG, "onAuthStateChanged:signed_out");
}
}
};
auth.addAuthStateListener(authListener);
}
private void addListeners() {
EmployeeProfile profile = ObjectGraph.getEmployeeProfile();
if (profile != null && profile.getMobile_no() != null && !profile.getMobile_no().trim().isEmpty()) {
reference.child(AppConstants.WORKINDIA_USERS_LAST_TIME).child(profile.getMobile_no().trim()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> child = (Map<String, Object>) dataSnapshot.getValue();
Log.e(TAG, "DATA " + child);
if (child == null) {
/*Query Listener Other listener*/
Query recentPostsQuery = reference.child(AppConstants.WORKINDIA_JOB_NODE).limitToFirst(1000);//.orderByChild("timestamp");
recentPostsQuery.addValueEventListener(jobBulKDownloadListener);
} else {
long lastSyncTime = (Long) child.get(AppConstants.TIMESTAMP);
Log.e(TAG, "DATA " + lastSyncTime);
/*Query Listener Other listener*/
Query recentPostsQuery = reference.child(AppConstants.WORKINDIA_JOB_NODE)
.orderByChild(AppConstants.TIMESTAMP)
.startAt(lastSyncTime)
.limitToFirst(1000);//.orderByChild("timestamp");
recentPostsQuery.addValueEventListener(jobBulKDownloadListener);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, databaseError.getMessage(), databaseError.toException());
}
});
}
}
private void register(final FirebaseAuth auth, final String email, final String password) {
Log.e(TAG, "register");
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.e(TAG, "register true");
signIn(auth, email, password);
} else {
Log.e(TAG, "register fail");
}
}
});
}
ValueEventListener jobBulKDownloadListener = new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Toast.makeText(getApplicationContext(), "jobBulKDownloadListener+ onDataChange", Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
#Override
public void run() {
try {
if (dataSnapshot != null) {
long time = System.currentTimeMillis();
Log.d(TAG, "Start Process : " + (System.currentTimeMillis() - time) / 1000 + " Seconds");
List<Job> jobs = new ArrayList<Job>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
WrapperJob job1 = snapshot.getValue(WrapperJob.class);
Job job = job1.getData();
jobs.add(job);
}
if (jobs.size() > 0) {
parseJobs(jobs);
}
Log.d(TAG, "After Process : " + (System.currentTimeMillis() - time) / 1000 + " Seconds");
}
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
Crashlytics.logException(e);
}
}
}).start();
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, databaseError.getMessage(), databaseError.toException());
}
};
private void parseJobs(List<Job> jobs) {
/* Job Operations*/
}
}
Why it is getting hanged ?? I have kept almost everything on background thread
This may not be the problem, but in your jobBulKDownloadListener it's probably safer to operate on the DataSnapshot on the main thread instead of your worker thread. You could refactor it like this:
ValueEventListener jobBulKDownloadListener = new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Toast.makeText(getApplicationContext(), "jobBulKDownloadListener+ onDataChange", Toast.LENGTH_SHORT).show();
if (dataSnapshot != null) {
final List<Job> jobs = new ArrayList<Job>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
WrapperJob job1 = snapshot.getValue(WrapperJob.class);
Job job = job1.getData();
jobs.add(job);
}
if (jobs.size() > 0) {
new Thread(new Runnable() {
#Override
public void run() {
try {
long time = System.currentTimeMillis();
Log.d(TAG, "Start Process : " + (System.currentTimeMillis() - time) / 1000 + " Seconds");
parseJobs(jobs);
Log.d(TAG, "After Process : " + (System.currentTimeMillis() - time) / 1000 + " Seconds");
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
Crashlytics.logException(e);
}
}
}).start();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, databaseError.getMessage(), databaseError.toException());
}
};