I'm having a problem with building Realm object which has a custom class.
#Parcel(
value = Parcel.Serialization.BEAN,
analyze = { Message.class })
#RealmClass
public class Message implements Comparable<Message>, RealmModel {`
#PrimaryKey
#Index
private long id;
#JsonProperty("thread_id")
long threadId;
#JsonProperty("message")
public String message;
#JsonProperty("user")
public User user;
...
}
When server send json response, try to parse as Message realm object with
realm.createObjectFromJson(MesssageMessage.class, JSONObject)
The problem is User. I've got an compile error "Filed user is not supported".
Below is the User class which is not realm object.
#JsonIgnoreProperties("incomplete_signed_up")
public class User implements KeepClassFromProguard, Parcelable {
public static final Parcelable.Creator<User> CREATOR = new
Parcelable.Creator<User>() {
#Override
public User createFromParcel(Parcel in) {
return new User(in);
}
#Override
public User[] newArray(int size) {
return new User[size];
}
};
public long id;
#JsonProperty("account_id")
private long accountId;
#JsonProperty("display_name")
public String display_name;
#JsonProperty("nick_name")
public String nickname;
#JsonProperty("user_detail")
public UserDetail userDetail;
...
}
I read https://gist.github.com/cmelchior/ddac8efd018123a1e53a and http://parceler.org/#getting_parceler, but I could't get answer yet.
I can't change every class to realm object because they all have another custom classes.
Does anyone know how this is handled? Hope there is any good example.
Thanks.
All references in a RealmModel must reference other RealmModel classes. This is the only way we can persist them.
You can #Ignore the user field, but then it will not be saved by Realm.
Related
public class User
extends RealmObject {
#PrimaryKey
private long id;
#Index
private String name;
private RealmList<MessageDetails> messageDetails;
//getter setter here
}
MessageDetails.class is here
public class MessageDetails extends RealmObject {
private Boolean isIncoming;
private String lastPosLeft;
private String message;
// getter setter here`}
button click for update list
int pos = myData.size();
mDetails = new MessageDetails();
mDetails.setMessage(etMessage.getText().toString());
mDetails.setIncoming(msgInOrOutBoolean);
mDetails.setLastPos(msgTypeOutgoingOrIncoming);
myData.add(pos,mDetails);
updateMsgInRealm();
**update list **
private void updateMsgInRealm() {
Realm realm = RealmManager.getRealm();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
final User user = realm.where(User.class).equalTo("id", mPref.getCurrentSelectedUserId()).findFirst();
assert user != null;
user.setMessageDetails(myData);
}
});
}
logs
e java.lang.IllegalArgumentException: 'value' is not a valid managed object.
at io.realm.ProxyState.checkValidObject(ProxyState.java:213)
at io.realm.com_example_dummychatapp_realm_UserRealmProxy.realmSet$messageDetails(com_example_dummychatapp_realm_UserRealmProxy.java:248)
at com.example.dummychatapp.realm.User.setMessageDetails(User.java:54)
at com.example.dummychatapp.MainActivity$2.execute(MainActivity.java:156)
at io.realm.Realm.executeTransaction(Realm.java:1493)
at com.example.dummychatapp.MainActivity.updateMsgInRealm(MainActivity.java:149)
at com.example.dummychatapp.MainActivity.onClick(MainActivity.java:217)
at android.view.View.performClick(View.java:6710)
at android.view.View.performClickInternal(View.java:6668)
at android.view.View.access$3400(View.java:797)
at android.view.View$PerformClick.run(View.java:26450)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
Here mPref.getCurrentSelectedUserId() is id stored in sharedPrefance
i got error while storing RealmList .
please if anyone can help me store list in realm db, i tried some code but not work for me if any sample code which fulfill my requirement suggest me here.
hey i got solution after wasting my whole day man here i listed problem
here i did wrong
enter int pos = myData.size();
mDetails = new MessageDetails();
mDetails.setMessage(etMessage.getText().toString());
mDetails.setIncoming(msgInOrOutBoolean);
mDetails.setLastPos(msgTypeOutgoingOrIncoming);
myData.add(pos,mDetails);
**use this **
MessageDetails mDetails = realm.createObject(MessageDetails.class);
mDetails.setMessage(etMessage.getText().toString());
mDetails.setIncoming(msgInOrOutBoolean);
mDetails.setLastPos(msgTypeOutgoingOrIncoming);
myData.add(pos,mDetails);
**and all you need to put above code inside **
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
// here you need to use above code
final User user = realm.where(User.class).equalTo("id", mPref.getCurrentSelectedUserId()).findFirst();
assert user != null;
user.setMessageDetails(myData);
}
});
I'm having an issue when I try to call addAll() on RealmList<Tile> with accounts which are already stored in realm file.
realmList.addAll(tiles) is called based on a response from an API call which may return Tiles containing one ore more accounts already stored in realm. The object return by the API looks like the one below:
public class ActivityStreamData extends RealmObject {
#PrimaryKey
private long id = DB_ID;
public String timestamp;
public RealmList<Tile> activity = new RealmList<>();
public MessageListMeta metadata = new MessageListMeta();
}
public class Tile extends RealmObject {
public String type;
public RealmList<Account> accounts;
public Account account;
}
public class Account extends RealmObject {
#PrimaryKey
public long id;
public String timestamp;
public String name;
public String email;
}
The call fails when trying to add tiles to the activityStream.activity list when fetching more.
Any way to force addAll to act as a createOrUpdate call
I have data in my firebase DB, everything works fine until I try to De-serialize the data.
Error: argument 1 has type io.realm.RealmList, got java.util.ArrayList
Here's my code:
DatabaseReference root = FirebaseDatabase.getInstance().
getReferenceFromUrl("https://swing-8792d.firebaseio.com/playlist");
Query playlistQuery = root.orderByKey().equalTo(key);
playlistQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Log.d("Child", child + "");
Playlist receivedPlaylist = child.getValue(Playlist.class);
Playlist playlist = new Playlist();
playlist.setCreatedBy(receivedPlaylist.getCreatedBy());
playlist.setName(receivedPlaylist.getName());
playlist.setMyMap(receivedPlaylist.getMyMap());
playlist.setQrKey(receivedPlaylist.getQrKey());
playlist.setCount(receivedPlaylist.getCount());
playlist.setId(receivedPlaylist.getId());
playlist.setTracks(receivedPlaylist.getTracks());
mPlaylist.add(playlist);
}
This is my POJO class:
#RealmClass
public class Playlist extends RealmObject {
String name;
Long id;
RealmList<Track> tracks;
Integer count;
String createdBy;
RealmList<UserMap> myMap;
String qrKey;
public RealmList<UserMap> getMyMap() {
return myMap;
}
public void setMyMap(RealmList<UserMap> myMap) {
this.myMap = myMap;
}
public Playlist(){}
public String getQrKey() {
return qrKey;
}
public void setQrKey(String qrKey) {
this.qrKey = qrKey;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public RealmList<Track> getTracks() {
return tracks;
}
public void setTracks(RealmList<Track> tracks) {
this.tracks = tracks;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
If I try to de-serialize with Normal POJO class (i.e Removing Realm) it works fine.
Firebase won't work with classes that do not have default constructor or private variables i.e no public getter/setter.
A easier solution in your case would be to make a middleware class that is the same pojo just not extending RealmObject. Next initialise your RealmObject subclass using the values of the pojo.
Pseudo code
class SimplePojoPlaylist {
public String variable;
}
class Playlist extends RealmObject {
public String variable;
}
Then first cast into SimplePojoPlaylist
for (DataSnapshot child : dataSnapshot.getChildren()) {
SimplePojoPlaylist receivedPlaylist = child.getValue(SimplePojoPlaylist.class);
Playlist playList = new Playlist();
playList.variable = receivedPlaylist.variable;
}
RealmList is not a supported type for deserialization. Your database checks its structure and deduces that tracks should be an ArrayList. Then, when it tries to convert it, it finds that the types do not match.
Check this link from the docs:
Also, it is a good practice to make your objects immutable to avoid unwanted access and/or modifications.
Creating an empty object from scratch and then calling setter methods to define its state is not a very good pattern, because it can create a situation where an object is accessed before when its state is "broken".
If you need to create an object that is flexible, has a few mandatory fields and some optional, consider using the Builder pattern, although to do it you'd have to redesign your model.
wikipedia - Builder
If you don't need/want to use a builder, my advice is:
1) Make the empty constructor private and create another public one that requires all the fields.
2) Change your tracks field to be of type "List". Then, if you need the object to return a RealmList create another getter method such as tracksAsRealmList() that makes a RealmList out of the member list and returns it.
3) Make sure that the "Track" model has an empty private constructor, a public one with all of its parameters and that all of its fields are supported by firebase deserialization.
4) Unless strictly necessary, make your object fields private and set its value through a setter method.
I hope this helps you.
I have data in my firebase DB, everything works fine until I try to De-serialize the data.
Error: argument 1 has type io.realm.RealmList, got java.util.ArrayList
Here's my code:
DatabaseReference root = FirebaseDatabase.getInstance().
getReferenceFromUrl("https://swing-8792d.firebaseio.com/playlist");
Query playlistQuery = root.orderByKey().equalTo(key);
playlistQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Log.d("Child", child + "");
Playlist receivedPlaylist = child.getValue(Playlist.class);
Playlist playlist = new Playlist();
playlist.setCreatedBy(receivedPlaylist.getCreatedBy());
playlist.setName(receivedPlaylist.getName());
playlist.setMyMap(receivedPlaylist.getMyMap());
playlist.setQrKey(receivedPlaylist.getQrKey());
playlist.setCount(receivedPlaylist.getCount());
playlist.setId(receivedPlaylist.getId());
playlist.setTracks(receivedPlaylist.getTracks());
mPlaylist.add(playlist);
}
This is my POJO class:
#RealmClass
public class Playlist extends RealmObject {
String name;
Long id;
RealmList<Track> tracks;
Integer count;
String createdBy;
RealmList<UserMap> myMap;
String qrKey;
public RealmList<UserMap> getMyMap() {
return myMap;
}
public void setMyMap(RealmList<UserMap> myMap) {
this.myMap = myMap;
}
public Playlist(){}
public String getQrKey() {
return qrKey;
}
public void setQrKey(String qrKey) {
this.qrKey = qrKey;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public RealmList<Track> getTracks() {
return tracks;
}
public void setTracks(RealmList<Track> tracks) {
this.tracks = tracks;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
If I try to de-serialize with Normal POJO class (i.e Removing Realm) it works fine.
Firebase won't work with classes that do not have default constructor or private variables i.e no public getter/setter.
A easier solution in your case would be to make a middleware class that is the same pojo just not extending RealmObject. Next initialise your RealmObject subclass using the values of the pojo.
Pseudo code
class SimplePojoPlaylist {
public String variable;
}
class Playlist extends RealmObject {
public String variable;
}
Then first cast into SimplePojoPlaylist
for (DataSnapshot child : dataSnapshot.getChildren()) {
SimplePojoPlaylist receivedPlaylist = child.getValue(SimplePojoPlaylist.class);
Playlist playList = new Playlist();
playList.variable = receivedPlaylist.variable;
}
RealmList is not a supported type for deserialization. Your database checks its structure and deduces that tracks should be an ArrayList. Then, when it tries to convert it, it finds that the types do not match.
Check this link from the docs:
Also, it is a good practice to make your objects immutable to avoid unwanted access and/or modifications.
Creating an empty object from scratch and then calling setter methods to define its state is not a very good pattern, because it can create a situation where an object is accessed before when its state is "broken".
If you need to create an object that is flexible, has a few mandatory fields and some optional, consider using the Builder pattern, although to do it you'd have to redesign your model.
wikipedia - Builder
If you don't need/want to use a builder, my advice is:
1) Make the empty constructor private and create another public one that requires all the fields.
2) Change your tracks field to be of type "List". Then, if you need the object to return a RealmList create another getter method such as tracksAsRealmList() that makes a RealmList out of the member list and returns it.
3) Make sure that the "Track" model has an empty private constructor, a public one with all of its parameters and that all of its fields are supported by firebase deserialization.
4) Unless strictly necessary, make your object fields private and set its value through a setter method.
I hope this helps you.
My JSON data looks like this from server api
{
//...
PredecessorIds:[[1,2][3,4][5]]
//...
}
I can successfully handle the arrays of Integer or String by RealmList<RealmInt> but this time I failed with an error, because RealmList> is not supported saying, "Type parameter 'io.realm.realmList' is not within its bounds...."
For RealmInt see this link.
I tried to solve it using RealmList<RealmLista> where RealmLista extends from RealmObject and has a RealmList like this
public class RealmLista extends RealmObject {
public RealmList<RealmInt> value;
public RealmLista() {
}
public RealmLista(RealmList<RealmInt> val) {
this.value = val;
}
}
and then created a RealmListaTypeAdapter and added it to Gson but when deserializing Gson expects an Object (RealmLista) but is found array, as the data shown above from server is obvious.
//RealmListAdapter for Gson
#Override
public RealmLista read(JsonReader in) throws IOException {
RealmLista lista = new RealmLista();
Gson gson = new Gson();
//how to read that [[1],[3,4]] int into RealmLista
in.beginArray();
while (in.hasNext()) {
lista.value.add(new RealmInt(in.nextInt()));
}
in.endArray();
return lista;
}
Is there any way to store a simple List<List<Integer>> by converting to RealmObject of any type while saving, List<List<Integer>> is easily converted by Gson. :-/
Realm doesn't support lists of lists currently. See https://github.com/realm/realm-java/issues/2549.
So #EpicPandaForce's idea about creating a RealmObject that holds that inner list is probably the best work-around.
It could look something like this:
public class Top extends RealmObject {
private RealmList<ChildList> list;
}
public class ChildList extends RealmObject {
private RealmList<RealmInt> list;
}
public class RealmInt extends RealmObject {
private int i;
}
The correct link for the gist should be: https://gist.github.com/cmelchior/1a97377df0c49cd4fca9