Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
It might be novice question but I am trying to write a result of selected location from place autocomplete fragment (or from custom Autocomplete edittext) to firebase database. As per firebase's documentation java objects are automatically mapped.
But, I am getting an error that the object has to be serialized when I am trying write my object into firebase.
Here is the Stacktrace:
2020-03-07 02:24:47.149 8708-8708/com.smslunchdelivery.smslunchdelivery E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.smslunchdelivery.smslunchdelivery, PID: 8708
com.google.firebase.database.DatabaseException: No properties to serialize found on class androidx.loader.app.LoaderManagerImpl
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.(com.google.firebase:firebase-database##19.2.0:547)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.loadOrCreateBeanMapperForClass(com.google.firebase:firebase-database##19.2.0:329)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.serialize(com.google.firebase:firebase-database##19.2.0:166)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.access$200(com.google.firebase:firebase-database##19.2.0:47)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.serialize(com.google.firebase:firebase-database##19.2.0:675)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.serialize(com.google.firebase:firebase-database##19.2.0:167)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.access$200(com.google.firebase:firebase-database##19.2.0:47)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper$BeanMapper.serialize(com.google.firebase:firebase-database##19.2.0:675)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.serialize(com.google.firebase:firebase-database##19.2.0:167)
at com.google.firebase.database.core.utilities.encoding.CustomClassMapper.convertToPlainJavaTypes(com.google.firebase:firebase-database##19.2.0:60)
at com.google.firebase.database.DatabaseReference.setValueInternal(com.google.firebase:firebase-database##19.2.0:282)
at com.google.firebase.database.DatabaseReference.setValue(com.google.firebase:firebase-database##19.2.0:159)
at com.smslunchdelivery.smslunchdelivery.FoodActivity.pushObjects(FoodActivity.java:237)
at com.smslunchdelivery.smslunchdelivery.FoodActivity.access$100(FoodActivity.java:48)
at com.smslunchdelivery.smslunchdelivery.FoodActivity$2.addToCardBtnClck(FoodActivity.java:175)
at com.smslunchdelivery.smslunchdelivery.FoodAdapter$4.onClick(FoodAdapter.java:113)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22265)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
My Object
public class User {
public Fragment placeAutoCompleteFragment;
public String email;
public User() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
public User(Fragment placeAutoCompleteFragment, String email) {
this.placeAutoCompleteFragment = placeAutoCompleteFragment;
this.email = email;
}
}
private void (String userId, String name, String email) {
//Getting error message here.
User user = new User(placeAutoCompleteFragment, email);
mDatabase.child("users").child(userId).setValue(user);
}
Firebase Documentation
private void writeNewUser(String userId, String name, String email) {
User user = new User(name, email);
mDatabase.child("users").child(userId).setValue(user);
}
My question is: What is the best possible way to achieve this?
Your User class is not suitable for automatic serialization to Firestore. The Fragment member is causing problems. A class you want to serialize should only contain primitive types, lists and maps, and other objects that only contain the same types of data. At the very minimum, remove the Fragment and find another way to deal with it outside of your POJO.
Firebase's documentation java objects are automatically mapped but the problem in here is that Fragment is an Android object, so it doesn't know how to serialize it.
Your data objects should be POJO (Plain Old Data Object) to be serialized and deserialized, there is no place for a Fragment in there or other android objects.
Related
When using Firebase to store and retrieve objects (POJOs) created by the user (for example: posts or comments), it becomes necessary to pass these objects around the application. But what is the suggested way to keep track of the associated DatabaseReference, location or unique key in the database for this object?
Example scenario
A simple to do list app allows the user to freely add, edit and remove items in their list. So when the user creates an item, something similar to the below would happen:
private Item storeItem(String title) {
String key = mDatabase.child("items").push().getKey(); // Where do we keep this key?
Item item = new Item(title);
mDatabase.child("items").child(key).setValue(item);
return item;
}
Where Item is this Java object:
public class Item {
private String title;
private String description;
public Item() {}
public Item(String title) {
this.title = title;
}
// ...
}
Behind the scenes, this item is added to a RecyclerView, either by inserting the returned Item to the adapter or when a ChildEventListener attached to the "items" reference is fired.
The user then wishes to rename this new item or add text to the description field, so tapping on it in the RecyclerView starts a separate Activity which receives the passed Item and uses getters/setters to make changes.
Now, we'll need to save these changes to the database, which we can do by calling setValue() again, as above. However, we didn't store the key variable from storeItem() so we don't actually know where this item is currently stored in the database.
So, where can we keep track of the created item's key for later use to save changes back to the database?
Possible solutions
There are a number of different paths we could take here, but I'm looking for some guidance on the suggested method, as the Firebase documentation doesn't mention this hurdle. I've outlined some examples that I can think of:
Store the key inside the object. We could add another field to the Item object to store the database key. So within the previous storeItem() method, the key variable is added to the Item constructor and stored in the database as a field.
Create a wrapper object. We could wrap the Item object in a container that has methods such as getItem() and getKey() or getDatabaseReference() and then pass this around the app instead of the Item itself.
Use the DataSnapshot instead. Once the item is created, wait until an attached listener receives it, then use and pass around the retrieved DataSnapshot, which has methods for getKey() and getRef().
Retrieve the object every time it is needed. Instead of passing Item around the app, we could retrieve it from the database every time it is needed, by using the key or DatabaseReference.
Wrapping up
Looking back on this huge question, it seems I might have overcomplicated it a little, but I wanted to be thorough in my explanation. I'm also hoping that it's not purely opinion-based and there currently is some standard way to achieve this.
So I guess my question is: is there a standard method to handle and make changes to Java objects stored in Firebase?
Most developers I see struggling with this end up storing the key inside the Java objects too. To prevent it being duplicated in the JSON, you can annotate it in the Java class:
public class Item {
private String title;
private String description;
#Exclude
public String key;
public Item() {}
public Item(String title) {
this.title = title;
}
// ...
}
See: Is there a way to store Key in class which I cast from Firebase object?
My personal preference in such cases is to keep the DataSnapshot around. The main disadvantage I see in that is that the information on the object-type of the snapshot is spreading out over my code since this exists in multiple places:
snapshot.getValue(Item.class);
I've been lobbying to generify the DataSnapshot class so that it'd become DataSnapshot<Item>, which would solve that problem. I think that is currently being considered in the Firestore SDK for JavaScript/TypeScript.
But lacking such a solution for the Android SDK for the Realtime Database, you're probably better off with the first approach: storing the key inside the Java objects.
I ran across a problem where I am not really sure how to solve it. The project I am working on currently has a model which partly consists of backend stored data and data from the local database.
So what I am trying to Archive is something like that:
Article : [Bunch of Information] & [boolean Subscribed]
The subscribed field is device bound and should not reflect any data on the backend. My question is if it is possible to implement in Room some kind of createIfNotExit() Method that handles the following cases:
Article not present locally: store a copy and set Subscribed to
false
Article present: update all the Information and Keep the
Subscribe-Flag untouched
My idea is to split the model into a separate Subscription-Model holding a reference to the Article. This way I could implement it simply via #Update(OnConfict=Update) etc...
Is there a way to implement a simple #Query method in the DAO that performs what I want?
Sorry if this is a really basic question but I couldn't find any material about best practices handling this case.
Thank you in advance!
For example, your entity is:
#Entity(tableName = "articles")
public final class Article {
#PrimaryKey
public long serverId;
public String title;
public String url;
public boolean isSubscribed;
}
You may write this method in DAO:
#Query("INSERT OR REPLACE INTO articles (serverId, title, url, isSubscribed) VALUES (:id, :title, :url,
COALESCE((SELECT isSubscribed FROM articles WHERE id = :id), 0));")
void insertOrUpdateArticle(long id, String title, String url);
Another option - write this logic in your repository and use two simple operations: select and update
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 5 years ago.
Improve this question
I have a simple question. I am developing an Android application that uses as backend Firebase realtime database. I was wondering if can it be said that my app is built following the MVC pattern, although I do not have my own logic, my own server, I am using the API from Firebase. Thanks!
Yes, you can use MVC pattern with Firebase. With Firebae it's even simpler. You can create a model class in which you can declare all the variables you need. This can include also other classes. Create all the constructors that you need. Add public setters and public getters and you'll have your complete model class or your POJO. Don't forget to add the no argument constructor needed for Firebase.
Here is an example of an user model class with only two fields.
public class UserModel implements Serializable {
private String userEmail;
private String userName;
public UserModel() {}
public void setUserEmail(String userEmail) {this.userEmail = userEmail;}
public String getUserEmail() {return userEmail;}
public void setUserName(String userName) {this.userName = userName;}
public String getUserName() {return userName;}
}
Every change that is made in your Firebase database is triggerd in real time in your user interface.
I recomand you reading the official documentation for Firebase. Here is how to add Firebase to your Android Project and here is how you can set up Firebase Realtime Database for Android. And here is how you can use FirebaseUI for Android.
Hope it helps.
This question already has answers here:
Cannot retrieve field values from realm object, values are null in debugger
(5 answers)
Closed 5 years ago.
I am trying to implement a generic realm wrapper. So, i can pass an object with its class to either add/update or get. I am using the realm browser to confirm that i am saving the data correctly, but when i perform a getAll query, i receive an array with the correct amount with the correct data structure but all the fields are in default values or null.
Here is my code :
Add RealmModel: (UserRealmModel)
#Override
public void putAll(Collection<RealmObject> realmModels) {
mRealm = Realm.getDefaultInstance();
mRealm.beginTransaction();
mRealm.copyToRealmOrUpdate(realmModels);
mRealm.commitTransaction();
}
GetAllRealmModels: (UserRealmModel)
#Override
public RealmResults getAll(Class clazz) {
return Realm.getDefaultInstance().allObjects(clazz);
}
I also tried:
#Override
public RealmResults getAll(Class clazz) {
return Realm.getDefaultInstance().where(clazz).findAll();
}
clazz = UserRealmModel.class
Output:
But whats interesting that in the debug view as shown in the screenshot, the toString method shows the correct data!
Help please :)
Mr Zeyad,
I went through Realm documentation for you. They have a well written document with an eample for your question.
They say,
Adding a watch in Android Studio on a RealmObject will display values of the fields. Unfortunately these values are wrong because the field values are not used. Realm creates a proxy object behind the scenes and overrides the getters and setters in order to access the persisted data in the Realm. Adding a watch for any of the accessors will yield correct values.
In the image above the debugger has stopped on line 113. There are three watch values, the person variable and the person.getName() and person.getAge() accessors. The code from lines 107 to 111 alters the person instance by changing the name and age. These values are then persisted in a transaction. On line 113, where the debugger is currently paused, the person watch instance is reporting on field values and they are incorrect. The watch values that use the accessor for person.getName() and person.getAge() report values that are correct.
Please note, the .toString() method will output the correct values but the watch panel will not (when watching a variable which is a RealmObject).
Read More Here
Hope it helps!
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.