How can I update a user field using Parse as backend? Here is the code:
for(ParseUser user : mFriends) {
if (user.get("phoneNumber").toString().equals(result.substring(3))) {
user.increment("field");
user.saveInBackground();
}
}
The problem is that if I use the current user (the user who's using the application) instead of user, it works, but I want to update the field of another user.
You are not allowed to modify objects you do not own unless you set up public ACLs for that object.
Please see Object-Level Access Control and ParseACL for details.
In addition, you should probably look into Relational Data to better model your data. You really should not be modifying a direct field of another User object.
Related
maybe the headline does not fit the question really well so I'll explain it.
In my app I send a request to a server to get gerneral user information. If I receive on I want to save it into the local room db. Now we come to the problem. I want to bind this one user to the view directly out of the db. But I can not bind a element, which maybe does not exists, because the request is in progress.
(My bad solution): Creating another livedate element which holds a boolean. I create a observer in the Activity and add the observer after the boolean observes a "true". With this solution I can not use "Data Binding" in the xml layout.
Does anyone have an idea? (If you need further information just ask - I know it is a really abstract question without any code)
As Sanlok Lee mentioned:
If you reassign user then it becomes a completely different instance and the observer will not listen to the new LiveData. Instead you can do val user: MediatorLiveData<User> and later you can call user.addSource(dao.getUserById(1), ...)
OR:
Just load the user (also if you know that there is no one in the DB) from the DB. You can do that in you UserRepository for example.
val user: LiveData<User> = userDao.getUser()
The Livedata will get notified when there is a valid user inserted.
I am having difficulty figuring out how user authentication/sign-in via FirebaseUI works in relation to the offline persistence of data from a Firestore database in Android.
I understand a user must be signed in in order to retrieve their documents from the database but what happens when the user is offline? How do I set up the flow of user and data checks in my app before displaying the user's list of documents, if any?
Please correct me if my understanding of the documentation (FirebaseUI and Firestore offline data) below is wrong.
So there are I think basically 3 pages a user would see:
A sign-up/sign-in page
An empty page when the user has no data in the database
A list of their documents
The first sign-up/sign-in page should be displayed for first time users and signed out users (whether the user has signed-out themselves or their sign-in token has expired). This is where FirebaseUI comes to the rescue. Can I check for both cases with just the getCurrentUser method? What does this method return when the user is offline? Have I missed this somewhere in the documentation on managing users?
The second empty page should be displayed for signed in users who don't have any data in the database (whether because they have just signed in for the first time or they have deleted all of their data). Do I use a get call to check for data? What does it return when there is no data or what listener do I have to use? Have I missed this somewhere in the documentation on getting data?
The third list page should be displayed for signed in users who have existing data or who have just created data/documents. This can be obtained with a query on a collection via a get call on that collection.
Finally, would you tie all this together from within one activity/fragment in the following way and order in onCreate/onCreateView?
First - Check for first time and signed out users: If yes then display (inflate) the first page (i.e. launch the FirebaseUI sign in intent activity). What happens after the user has signed up/signed in? Is the user brought back to the originating activity/fragment? How do I handle this?
Second - Check for data in the database: If there is no data then display an 'empty' page. If there is data then display the list of documents instead. It seems this can be handled by switching visibility between say a TextView with the text "Empty" and the RecyclerView in the same layout (see this SO post).
Please help!
Can I check for both cases with just the getCurrentUser method? What does this method return when the user is offline?
When calling getCurrentUser() method on a FirebaseAuth object it returns an object of type FirebaseUser if the authentication process is successful.
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
But before that you need to instantiate the firebaseAuth object by calling the static FirebaseAuth.getInstance() method like this:
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
So if the authentication process is successful and you are getting offline, it doesn't matter, calling getCurrentUser() will always return the FirebaseUser object.
Do I use a get call to check for data?
Yes, you should use a get() call and first time check if (task.isSuccessful()) and second if the data exist at a particular location.
What does it return when there is no data or what listener do I have to use?
It will return an empty DocumentSnapshot object. So first you'll need to use a get() and use the addOnCompleteListener().
This can be obtained with a query on a collection via a get call on that collection.
Yes that's correct.
Finally, would you tie all this together from within one activity/fragment in the following way and order in onCreate/onCreateView?
Yes, you can tie all this together from within one activity/fragment.
What happens after the user has signed up/signed in? Is the user brought back to the originating activity/fragment? How do I handle this?
If the user signs out, you should redirect the user to the LoginActivity. I have exaplained in one of my tutorials step by step, the entire authentication process using Google and Firebase.
Check for data in the database: If there is no data then display an 'empty' page.
This is a recommended way in which you can retrieve data from a Cloud Firestore database and display it in a RecyclerView using FirestoreRecyclerAdapter. So in such case you can override the onDataChanged() like this:
#Override
public void onDataChanged() {
if (getItemCount() == 0) {
recyclerView.setVisibility(View.GONE);
emptyView.setVisibility(View.VISIBLE);
} else {
recyclerView.setVisibility(View.VISIBLE);
emptyView.setVisibility(View.GONE);
}
}
I want to get the data stored in the DB without being restricted to access it only when there is a data change.
I've seen this post from 2016:
How to access Firebase data without using addValueEventListener
Which suggested to use addValueEventListener.
I've also seen this post:
Accessing data in Firebase databse
Without good answer.
ValueEventListener will trigger the onDataChange only when the database will have a change.
How else can I access the database without something being changed in the database?
For now I will write simple harmless change in order to access the data, but i'm wondering if it's the only way to do it.
Thanks
Of course this is absolutely not true. You can retrieve data whenever you like to.
Firstly I would like to advice you to read this documentation reference.
Secondly I provide you with what you really asked for.
If you read the documentation you will notice that it states the following:
The onDataChange() method in this class is triggered once when the listener is attached and again every time the data changes, including the children.
That means that with this code:
databaseReference.removeEventListener(eventListener);
With that method you would be able to detatch any listener so it only listens once or detatch it whenever you want to.
There is a method for only retrieving data once though.
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(TAG, "Data retrieved.");
}
...
}
This method will exactly call onDataChange once or respectively onCancelled.
I have a custom boolean field called Approved in my custom ParseUser object. We change this field from false to true via a web app. According to the documentation, I should be able to update currentUser after changing the flag with fetchInBackground(), like this:
ParseUser.getCurrentUser().fetchInBackground(new GetCallback<ParseObject>() {
#Override
public void done(ParseObject parseObject, ParseException e) {
Log.v("qwer", "fetched User: " + ((CustomUser)parseObject).isApproved());
}
});
But even though the approved flag has been set to true, the result coming back from the server is always false. Unless I logout and login again, at which point currentUser and the respective field is synced with the server.
Why doesn't fetchInBackground() work for the local user, and if I'm using it incorrectly, how do I update the currentUser.
Please see this link, the point is to use pinInBackground and also enable local datastore with Parse.enableLocalDatastore(yourContext); in your Application class.
Update:
Not sure if this will help you, but I do have a similar situation with you:
I do a typical user.put("userVerified", true); then user.saveInBackground to save a boolean that indicates whether user has been verified, then in the next activity I use user.getBoolean("userVerified") to retrieve the flag...Would this be something you might consider?
I a parse class called Booking which has pointers to Parse classes: Ticketand _User and other irrelevant fields.
Where Ticket has pointers to Location and more irrelevant fields.
Most classes other than the Booking class has Class level Access List Restrictions, which is necessary for the security of my app.
The following is the code I use to attempt to save a booking object using the android SDK:
final Booking booking = new Booking();
// For pointer like behaviour
Ticket ticketPointer = Ticket.createWithoutData(Ticket.class, bookingData.getTicket().getObjectId());
booking.setTicket(ticketPointer);
ArrayList<Coupon> couponPointers = new ArrayList<>();
for (Coupon coupon : bookingData.getCoupons()) {
// For pointer like behaviour
couponPointers.add(Coupon.createWithoutData(Coupon.class, coupon.getObjectId()));
}
booking.setCoupons(couponPointers);
booking.setClient(ParseUser.getCurrentUser());
booking.setTicketCount(bookingData.getTicketCount());
booking.setPaymentMethod(Booking.PaymentMethod.CASH_ON_ARRIVAL);
booking.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (asserter.assertPointerQuietly(e)) {
e.printStackTrace();
} else {
l.d("Successfully posted a booking request on server");
}
}
});
The problem is that parse saves object recursively, so even objects pointed to by the pointers are saved along with the object being saved. And since the other classes can't be accessed by regular users, exceptions are raised when attempts to save these objects pointed to by the pointers are made. So, I put the ticket and coupon objects into the booking object in the form of pointers using the createWithoutData method as marked in comments as // For pointer like behaviour as per the solution to saving pointers here.
All this works well, and I got rid of exceptions raised by accessing the Ticket and the Coupon class which were saved recursively.
However, to my surprise, the above code results in another exception caused by an attempt to access the Location class which is pointed to by the pointer of the Ticket object which is pointed to by the Booking object(2nd level pointer)!!!.
Is there any way to prevent the location object from being pointed to? An ideal solution would be to disable recursive saves in the first place, but any solution would be appreciated.
A workarounds exist, but it is ugly, and I would like to avoid it: It involves using a string representation of the object id of the object instead of the pointer.