I have a project where I am reading some json through GSON and Volley. I want to save my data in a database, and I was hoping that Realm would be a good solution. I took my first class which has seven member variables, all Strings and ints and had it extend RealmObject and identified one of the ints as the primary key. It compiles fine, but when it runs, I get tons and tons of output in the logs, and eventually the app just crashes before showing the main activity. It seems that GSON does not like parsing a class that has extended RealmObject.
So I did some searching and I found this post from the Realm site, but it is for an older version of Realm (I am currently using 0.87)
https://realm.io/docs/java/0.77.0/#other-libraries
It gives a solution, but I can't get that solution working for me because they are parsing their GSON differently that I am. Maybe we can solve this by just helping me here, but I wonder if this soltution won't work not matter since it is for an older version?? Anyway, I am parsing my GSON like this:
private void DisplayData(int count, final ArrayList<TwoLineSummaryCardDataObject> tlscdo,
final TwoLineSummaryViewAdapter lsva) {
final String url = "https://mydata.com/mydata";
final GsonRequest gsonRequest =
new GsonRequest(url, MyData.class, null, new Response.Listener<MyData>() {
#Override
public void onResponse(MyData myData) {
tlscdo.clear();
// Disable Realm stuff for now
//Realm realm = Realm.getDefaultInstance();
//realm.beginTransaction();
for (int i = 0; i < myData.getData().size(); i++) {
tlscdo.add(new TwoLineSummaryCardDataObject(myData.getData().get(i)));
//realm.copyToRealmOrUpdate(myData.getData().get(i));
}
//realm.commitTransaction();
lsva.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
if(volleyError != null) Log.e("MainActivity", volleyError.getMessage());
Toast.makeText(MainActivity.this, "Error in Volley", Toast.LENGTH_SHORT).show();
}
}
);
// Add the request to the queue
Volley.newRequestQueue(this).add(gsonRequest);
VolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(gsonRequest);
1) How do I update my code so I can use a GsonBuilder like the example on the Realm javadoc page?
2) Am I wasting my time because that code is for an older version of Realm and there is now a different/better/no way to make GSON and Realm play together?
Edit: There was a req to see the MyData class. It's really simple:
public class MyData {
#PrimaryKey
private Integer id;
private String name;
private String abbrev;
private String countryCode;
private Integer type;
private String infoURL;
private String wikiURL;
// followed by a bunch of getters and setters
}
To clarify, it runs fine like this. If I add "extends RealmObject", it will still compile, but when running, it just spews out all kinds of messages and then the app eventually crashes (out of memory, I presume) after a few seconds without ever showing the activity.
Edit 2, adding in the logcat as requested.
When I do run it with the "extends RealmObject", this is the logcat.
http://pastebin.com/raw/1VZq8bQD
And if I take the "extends RealmObject" out, it runs perfectly.
1) How do I update my code so I can use a GsonBuilder like the example on the Realm javadoc page?
You can create a new class that extends Request<T> and apply it to your existing code. In your case, the quickest way is to copy the GsonRequest class source code to a new one, and modify the line that intialize the Gson object in the constructor:
mGson = new Gson();
with the code as written in realm.io's website.
2) Am I wasting my time because that code is for an older version of Realm and there is now a different/better/no way to make GSON and Realm play together?
As of writing this answer, the lastest version of realm is 0.87.1, and the method of working with GSON is the same. So this should still be the proper way.
Related
Thanks in advance.
I have scenario where i wanted to check the data difference between existing and new realm model object.
Example
public class PostModel extends RealmObject {
#Required
#PrimaryKey
#Index
private String postId;
private String message;
}
Let say we have two objects
Old
PostModel old = new PostModel("one", "Welcome");
realm.copyToRealm(old);
New Object
PostModel newOne = new PostModel("one", "Welcome to World");
before updating the old object with newOne should check data change, if change is there then should insert in the realm, like below
realm.dirtyCheckAndUpdate(old, newOne);
//underlying it should do below
Getting the record with id "one"
Check the difference between db record and new record (!old.message.equalsIgnore(newOne.message)).
if change is there then copyToRealmOrUpdate() should happen.
I just gave an example, i need to to this for complex RealmModel with relationship.
Why do you need to check? You can just call copyToRealmOrUpdate()? It will update data regardless, but if it overrides the data with the same data the end result is the same.
Otherwise, you will be forced to implement all the checking yourself, which is time-consuming and error-prone. You could also make your own annotation processor that generated the logic for you. It would look something like:
public boolean compare(PostModel m1, PostModel m2) {
if (!m1.getId().equals(m2.getId()) return false;
if (!m1.getMessage().equals(m2.getMessage()) return false;
if (!PostModelReference.compare(m1.getRef(), m2.getRef()) return false; // Recursive checks
}
I am about to start development on an Android app. I am interested in using Otto or EventBus in my app to assist with making asynchronous REST network calls and notifying the main thread when the calls have returned.The one major flaw with the use of these busses that I have found during research is that there are typically too many event classes that have to be created. Are there any patterns or approaches to reduce the number of event classes that have to be used?
The concept
The best way i have solved the issue of too many event classes is by using Static Nested Classes You can read up more about them here.
Now using the above concept here is how you would solve the problem:
So basically suppose you have a class called Doctor that you are using to create an object you are passing around with your application. However you want to send the same Object over the network and retrieve JSON in the context of that same object and feed it back to a subscriber to do something with. You would probably create 2 classes
DoctorJsonObject.java that contains information about the returned JSON data and
DoctorObject.java that has data you are passing around in your app.
You don't need to do that.
Instead do this:
public class Doctor{
static class JSONData{
String name;
String ward;
String id;
//Add your getters and setter
}
static class AppData{
public AppData(String username, String password){
//do something within your constructor
}
String username;
String password;
//Add your getters and setters
}
}
Now you have one Doctors Class that Encapsulates both the events for the post to the network and the post back from the network.
Doctor.JSONData represents data returned from the network in Json format.
Doctor.AppData represents "model" data being passed around in the app.
To use the class' AppData object then for the post event:
/*
You would post data from a fragment to fetch data from your server.
The data being posted within your app lets say is packaged as a doctor
object with a doctors username and password.
*/
public function postRequest(){
bus.post(new Doctor.AppData("doctors_username","doctros_password"));
}
The subscriber within you implementation that listens for this object and makes an http request and returns the Doctor.JSONData:
/*
retrofit implementation containing
the listener for that doctor's post
*/
#Subscribe
public void doctorsLogin(Doctor.AppData doc){
//put the Doctor.JSONObject in the callback
api.getDoctor(doc.getDoctorsName(), doc.getPassWord(), new Callback<Doctor.JSONObject>() {
#Override
public void success(Doctor.JSONObject doc, Response response) {
bus.post(doc);
}
#Override
public void failure(RetrofitError e) {
//handle error
}
});
}
}
With the above implementation you have encapsulated all Doctor Object related events within ONE Doctor class and accessed the different types of objects you need at different times using static inner classes. Less classes more structure.
I am having trouble using a query in realm.io. My code:
public static void delete(Context context, Workday workday) {
Realm realm = getRealm(context);
realm.beginTransaction();
RealmResults<Workday> workdays = realm.where(Workday.class)
.equalTo("date", workday.getDate())
.equalTo("hours", workday.getHours())
.equalTo("minutes", workday.getMinutes())
.findAll();
workdays.remove(0);
realm.commitTransaction();
}
Debug:
Why is the data visible in the JSON line but not in the fields itself? What am I doing wrong?
Thanks in advance!
UPDATE:
This is my delete function and it does find the workday1 object:
public static void delete(Context context, Workday workday) {
Realm realm = getRealm(context);
realm.beginTransaction();
Workday workday1 = realm.where(Workday.class)
.equalTo("date", workday.getDate())
.equalTo("hours", workday.getHours())
.equalTo("minutes", workday.getMinutes())
.findFirst();
workday1.removeFromRealm();
realm.commitTransaction();
}
When it executes the removeFromRealm method it crashes:
java.lang.IllegalStateException: Illegal State: Row/Object is no longer valid to operate on. Was it deleted?
How can I fix this?
You're doing nothing wrong! :)
Realm proxies your objects so that there won't be copies of your data all over the place. The getters and setters are overridden by the proxy classes and access your data directly in Realm. Of course this makes it harder to inspect the objects during debug, as you could notice, but that's why we've also overridden toString() to show something meaningful.
I'm using Google's mobile backend starter for a project and I want to set the key name myself for some of entities instead of using the auto-generated one.
If I were doing this without the backend I could do something like it describes in the datastore documentation which creates an employee entity with the key name "asalieri":
Entity employee = new Entity("Employee", "asalieri");
Here's the code I'm using to create the entity. I've been trying to use the CloudEntity.setId() function. Upc is a string and it doesn't work when I use a hardcoded string either.
CloudEntity avg = new CloudEntity("Aggregate");
avg.setId(upc);
avg.put("averagePrice", sum/count);
insertAverage(avg);
private void insertAverage(CloudEntity avg) {
CloudCallbackHandler<CloudEntity> handler = new CloudCallbackHandler<CloudEntity>() {
#Override
public void onComplete(final CloudEntity result) {
Toast.makeText(AddProduct.this, "Average updated.", Toast.LENGTH_LONG).show();
}
#Override
public void onError(final IOException exception) {
handleEndpointException(exception);
}
};
// execute the insertion with the handler
getCloudBackend().insert(avg, handler);
}
When I run the app everything works fine except that the new entity doesn't have the custom ID that I set.
The only thing I can think of is that setId() isn't supposed to do what I think it does but I've been digging through the code and haven't been able to find another way to do what I want.
Does anyone know why this isn't working?
I'm a Googler on the MBS project. I recreated your issue and first glance shows this as a bug on our side. I'll edit my response with updates.
Would this workaround be ok until we push a fix?
avg.put("samId", upc)
In android, I'm using model classes with methods to handle the data manipulation. My data is brought in from webservices as json. I'm contemplating the possibility of using JSONObjects to store the values of class level attributes. But, I don't know of a way to use the JSONObj as the "holder" variable and create access methods. I don't want to predetermine these methods, as jsonRepository should hold the values, not always known at design time
For example, I'd like to have:
public class User {
private JSONObject jsonAttributes;
public User(String json) {
this.jsonAttributes= new JSONObject(json);
}
[IMPLICIT attribute access methods]
public string Prop1() returns jsonAttributes.getString("prop1");
public string Prop1(String newProp1) returns jsonAttributes.putString("prop1",newProp1);
public string Prop2() returns jsonRepository.getString("id");
public string Prop2(String newProp2) returns jsonAttributes.putString("prop2",newProp2);
....
from outside this class then, I would access the attributes simply...
User myUser = new User(someValidJson);
String myString = myUser.Prop1
Misguided? If not, how does one manage implicit property setting/getting?
As was mentioned in the comment above, why not create your user class, with all of the relevant memeber variables, and simply parse your JSON data in order to populate the ionformation in your user class.
There are a lot of ways you can do this, but I would consider using the builder pattern, as it is flexible, which could be useful if your JSON data changes in the future.