Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm migrating to Backendless from Parse and is currently trying to do something that was pretty obvious with Parse.
I'm creating a class:
#ParseClassName("UserPreferences")
public class UserPreferences extends ParseObject {
public ParseFile getBackground(){
return getParseFile("background.jpg");
}
public boolean getAudioStatus(){
return getBoolean("audio");
}
public void setAudioStatus(boolean status){
put("audio", status);
}
}
Now I want to assign this class to the currently logged in user as a pointer:
UserPreferences userPrefs = new UserPreferences();
userPrefs.setAudioStatus(true);
ParseUser user = ParseUser.getCurrentUser();
user.put("prefs", userPrefs);
userPrefs.saveInBackground()
user.saveInBackground(); //again, use SaveCallback
and to retrieve all values etc to be applied to local preferences:
ParseUser user = ParseUser.getCurrentUser();
UserPreferences userPrefs = user.getParseObject("prefs");
userPrefs.fetchInBackground();
This way, the user's data is always tied to himself and objectID etc isn't a problem.
Now I didn't work this out myself when using Parse. So unfortunately I can't really talk for this matter. I just hope someone more experienced see's what I'm doing and can relate this into translating it to Backendless SDK and workflow somehow?
You do not need to extend any specialized Backendless classes in the objects you save/load to/from Backendless. In the classes you can use either public fields or getter/setter properties. You do not need to use any annotations. Things are much simpler. If you have a class A which references class B (via a field or a javabean property), then on the backend, we will store A in a table called "A" and B in a table called "B". We will also create a relation between the two records on the backend.
There are two ways you could handle what you showed with Backendless:
Saving user object with preferences:
BackendlessUser user = Backendless.UserService.CurrentUser();
user.setProperty( "audioStatus", true );
user.setProperty( "backgroundImageUrl", url-to-background-jpg );
Backendless.UserService.save( user, asyncCallback );
This will result in creating two columns in the Users table: "audioStatus" and "backgroundFile". If, however, you want to have a separate table where all the preferences are, you could do this:
public class UserPreferences
{
// or use Java bean getter/setter instead of fields
public String backgroundImageUrl;
public boolean audioStatus;
}
UserPreferences prefs = new UserPreferences();
prefs.backgroundImageUrl = url-to-background-jpg;
prefs.audioStatus = true;
BackendlessUser user = Backendless.UserService.CurrentUser();
user.setProperty( "userPrefs", prefs );
Backendless.UserService.save( user, asyncCallback );
This will result in a secondary table created on the backend. The table will be called "UserPreferences" - just like the class name. Backendless will also create a relationship between the user object and the specific record in the UserPreferences table.
Retrieving user properties
If the user properties are not stored via a relation (see the first sample above), then they are loaded right away when the user logs in. Then you can get the properties with the getProperty method:
Backendless.UserService.login( userName, password, new AsyncCallback<BackendlessUser>()
{
#Override
public void handleResponse( BackendlessUser user )
{
boolean audioStatus = (boolean) user.getProperty( "audioStatus" );
String fileUrl = (String) user.getProperty( "backgroundImageUrl" );
}
#Override
public void handleFault( BackendlessFault backendlessFault )
{
}
});
If the preferences are stored in a related table, then you have several options to load them:
BackendlessUser user = Backendless.UserService.CurrentUser();
ArrayList<String> relations = new ArrayList<String>();
relations.add( "userPrefs" ); // name of the relation column in Users
Backendless.Data.of( BackendlessUser.class ).loadRelations( user, relations, new AsyncCallback<BackendlessUser>()
{
#Override
public void handleResponse( BackendlessUser user )
{
// user - object with loaded relations.
// now you can do this:
UserPreferences prefs = (UserPreferences)user.getProperty( "userPrefs" );
}
#Override
public void handleFault( BackendlessFault backendlessFault )
{
}
});
Hope this helps!
Related
I'm trying to make a class with some methods to get user's info. I'm making it like libraries.
For example, the current logged in user has some data in firestore. Say I want to retrieve his username.
This is placed in the same activity where I want to retrieve the username.
String currentUserUsername;
private String getUserUsername(DocumentReference currentUserDocument) {
currentUserDocument.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
currentUserUsername = documentSnapshot.getString("username");
}
});
return currentUserUsername;
}
And I'm calling getUserUsername(currentUserDocument) after activity onCreate so I can use currentUserUsername anywhere I want in the code. But the problem is that I'm doing this in many activities. How can I make it like a public class like those libraries?
I am working on an Android app with 2 types of users (doctors and patients), and I want each type to have their own UI. For eg, doctors must see ' Add days off' and patients must see ' Book appointment' . Somehow I don't get anywhere with whatever I try.
I also use Firebase Auth and Realtime Database which makes the user type retrieval kinda tricky. So far I've tried a lot of Async classes, methods, variables, shared preferences, retrieving data while on launcher splash screen.
The best I got is getting the user to login, it shows the good layout, then I start the app again and it shows the wrong layout. Somehow I noticed it just works on the second run, but not always so the behaviour is unpredictable to me at least. But at least the user type from the database is retrieved.
I have a class that extends Application, which checks if there's an user authenticated and then redirects the user to either LoginActivity, or MainMenuActivity.
I have created a method that retrieves the Firebase Auth user data from Realtime Database, looping through both Doctors and Patients 'children' until it finds the current user email and gets its type. Since Realtime Database is asynchronous, the methos gets an interface as an argument, and after the loop, the I call the interface's method, which sets a static boolean variable (isUserDoctor).
Before setting the content view (with 2 possible layouts), I call the function described before and it works the way I first mentioned, which is not good.
The method that retrives data
public void getUserType(final DataStatus dataStatus) {
currentUser = FirebaseAuth.getInstance().getCurrentUser();
currentUserEmail = currentUser.getEmail();
databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
currentUserType.clear();
FirebaseManager.isUserDoctor = false;
DataSnapshot allDoctors = dataSnapshot.child("Doctors");
DataSnapshot allPatients = dataSnapshot.child("Patients");
for (DataSnapshot ds : allDoctors.getChildren()) {
if (currentUserEmail.equals(Utils.decodeUserEmail(ds.getKey()))) {
currentUserType.add(ds.child("userType").getValue().toString());
} else {
for (DataSnapshot dsPacient : allPatients.getChildren()) {
if (currentUserEmail.equals(Utils.decodeUserEmail(dsPacient.getKey()))) {
currentUserType.add(dsPacient.child("userType").getValue().toString());
}
}
}
}
dataStatus.DataIsLoaded(currentUserType.get(0).toString());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
The interface
public interface DataStatus {
void DataIsLoaded(String userType);
}
The method's call in Main Menu
FirebaseManager.getInstance().getUserType(new DataStatus() {
#Override
public void DataIsLoaded(String userType) {
if ("doctor".equals(userType))
FirebaseManager.isUserDoctor = true;
else
FirebaseManager.isUserDoctor = false;
}
});
if (FirebaseManager.isUserDoctor)
setContentView(R.layout.activity_main_menu_doctor);
else
setContentView(R.layout.activity_main_menu);
So if anyone has any ideas about how to show the proper layout and allow functions based on user role/type please share. What I basically need is to retrieve the userType from the current email just in time to set a variable needed throughout the whole app in order to hide/show certain views.
HelloBelow is my database structure
I want to first get results from post object and using "userid" from that I want to get results from Users Object.
I want to update ViewModel with the above results that contain fields that are in both the objects
How to achieve this ?
I have written code to get the result from post object but how to again make call to get user object and update viewmodel and livedata object
private static final DatabaseReference POST_REF =
FirebaseDatabase.getInstance().getReference("/Post");
private final FirebaseQueryLiveData liveData = new
FirebaseQueryLiveData(POST_REF);
#NonNull
public LiveData<DataSnapshot> getDataSnapshotLiveData() {
return liveData;
}
There are different ways to model you database to archive this, It is always good to follow best practices see: https://firebase.google.com/docs/database/android/structure-data#best_practices_for_data_structure
In this case, since you only want the Profile Pic and name I would save it directly into the object:
{
"Posts":{
"post1":
{
"likes":23,
"userId":"id",
"user":
{
"imageUrl":"url",
"name":"Name"
}
}
}
}
Of course, the tradeoff is that the image URL won’t be updated if the user node gets updated (unless you code something to update it in a Cloud Function for example)
On the other hand, you could also perform those two calls to the Firebase Realtime Database (one to get the post, and the other to get the user data):
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Post post = dataSnapshot.getValue(Post.class);
ValueEventListener userListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot userDataSnapshot) {
post.setUser(userDataSnapshot.getValue(User.class);)
}
};
mUserReference.addListenerForSingleValueEvent(userListener);//only fetch data once
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
mPostReference.addValueEventListener(postListener);
EDIT:
Having the user object inside the post would work using the architecture components (Just be sure to have the proper class to deserialize), on the other hand, since you are using the FirebaseQueryLiveData https://firebase.googleblog.com/2017/12/using-android-architecture-components.html and may want to avoid writing the user on that post node, I think you can have both ViewModels with different Database references, and once the data is fetched you could just update the post object e.g. post.setUser(user) with the user obtained from the other ViewModel Observer and then update the UI. You could also have a HashMap to keep track of what post needs what user, although this answer looks like a way to go: https://stackoverflow.com/a/46483213/1537389. Hope that helps
I have an existing array that I created locally and import to Firebase and my array looks like this.
These both elements are objects created that have some many information related to appointments.
Now i am trying to create a new element with the same form, for example:
2--
|__ And the object I have created in my app
I have only managed or eliminate the rest of the elements (with setValue(object))
Appointment newAppointment = new Appointment.Builder()
.fechacita(dateSelected)
.horacita(hourSelected)
.usertoken(mAuthManager.getCurrentUserId())
.oficina(centerSelected)
.build();
mDatabaseRef.child("LISTACITAS").setValue(newAppointment);
or create it with an ID that when recovering the data causes a crash in the application due to the deserialization of the objects that are not equal.
The Appointment object that I want to insert is
public class Appointment implements Parcelable {
private String fechacita;
private String horacita;
private Office oficina;
private String userID;
.....
}
The class is a normal Parcelable class that generates an object with her builder.
Please some help...
try this code
mDatabaseRef.push().setValue(incidentReportUser)
Write it this way (push() adds values instead of overriding).
Ans from here
UPDATE 1
if you want a series in key, not some random value, try this:
get the last key in the list using
Query dbQry = mDatabaseRef.orderByKey().limitToLast(1);
dbQry.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int key = Integer.parseInt(dataSnapshot.getKey());
//Increment the key and add the object here using the earlier method
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
}
I have not checked this as of now, but you could get the idea
I have the following data structure on firebase for the user MF0qeRA4p7djfjgXxqwFOck3m6p02. I want to get the value of item3 to populate a single field into the User interface on an Android App. I have been looking through samples on Stackoverflow, but all I have found are outdated and do not work with the current version of firebase. I'm new to firebase completely and this is my first app on android. I've got the oncreate user method to populate the users email address and add the 4 item fields, but retrieving the data I'm completely lost and I am not sure where to even begin.
-Users
---MF0qeRA4p7djfjgXxqwFOck3m6p02
------item1:"1"
------item2:"2"
------item3:"3"
------item4:"4"
According to what I can identify is, you are facing problem retrieving data from this reference. Here is the code:
final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.child("MF0qeRA4p7djfjgXxqwFOck3m6p02").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map=(Map<String, Object>)dataSnapshot.getValue();
String item3=(String)map.get("item3");
display(item3);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Hope this helps.
You can create a custom model and inside you can insert elements. Something like this:
public class Item {
private List<Object> ojects;
}
There you can save instance of Item on database. In this case you have more controll. Other case is to use push() method, that will generate a new encoded key, something like this:
mDatabase.child("items").push().put(new Object());