How to store a object array by using Room in Android? - android

I want to cache a song-list in my app, the Song-list structure is like below:
#Entity
public class Songlist {
String _id;
String desc;
List<SongDesc> songWithComment;
.....
public static class SongDesc {
String comment;
Song song;
}
}
#Entity
pulbic class Song {
String name;
String type;
......
}
The lib of operating sqlite3 is android.arch.persistence.room, but it dosen't allow object references in a table.Is there any way to cache a song-list by using Room in Android?

Also if you want to store some custom objects, you can use #Embedded annotation like in example bellow :
class Address {
public String street;
public String state;
public String city;
#ColumnInfo(name = "post_code")
public int postCode;
}
#Entity
class User {
#PrimaryKey
public int id;
public String firstName;
#Embedded
public Address address;
}

If you want to save an ArrayList of some type into the database, you shuld use TypeConverter to convert the ArrayList from and into a simpler recognizable type to the database engine, like a String.
See this:
Android Room Database: How to handle Arraylist in an Entity?
and https://commonsware.com/AndroidArch/previews/room-and-custom-types

Related

Android Firebase, Unable to fetch the data

I created a family tree application on java and mysql database. Now I am testing an android app for the same. So I converted my mysql database file to JSON format and uploaded it to firebase. When I am inserting records on it, it is working perfectly fine but when I try to fetch the data it is showing the error:
com.google.firebase.database.DatabaseException: Failed to convert a value of type java.lang.String to int
at com.google.android.gms.internal.firebase_database.zzkt.zzb(Unknown Source:180)
What should be the problem? I tried deleting the data from the database which I uploaded through JSON file and then inserted records directly from app into database and fetch them, it worked fine but when I am adding record from JSON file only then It is creating problem.
here is the code from the app for fetching data:
public void clicked(){
mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Family> FamilyList = new ArrayList<>();
for (DataSnapshot adSnapshot: dataSnapshot.getChildren()) {
Family f = adSnapshot.getValue(Family.class);
FamilyList.add(f);
// adsList.add(adSnapshot.getValue(Family.class));
}
Toast.makeText(MainActivity.this, "Total Records: "+FamilyList.size(), Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Family Model Class:
public class Family {
int id;
String name;
String fatherName;
int fid;
String city;
String state;
public Family(int id, String name, String fatherName, int fid, String city, String state) {
this.id = id;
this.name = name;
this.fatherName = fatherName;
this.fid = fid;
this.city = city;
this.state = state;
}
public Family()
{
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFatherName() {
return fatherName;
}
public void setFatherName(String fatherName) {
this.fatherName = fatherName;
}
public int getFid() {
return fid;
}
public void setFid(int fid) {
this.fid = fid;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
Here is the JSON Record Sample
It is the records which I entered through App
I think the converted JSON treated id and fid as String, while in mySQL they are int. (am I correct?)
Tell me if any other code is needed.
The problem relies on here
Family f = adSnapshot.getValue(Family.class);
you are trying to get data in an inappropriate type.
You should correct this by checking Family.class and check if the values there are the same as they are in your database structure in firebase, it will be helpful if you put your database structure here, or some images.
Check if for example in Family.class you have in your variable types the same as they are in firebase, with the same name also.
So for example if in firebase there is an string called name you should have in your constructor inside Family.class the same type and name.
String name;
and in Firebase your json key should be name too.
For instance, check this
your Family class for example should have the variables with the same name and type as your database.
Also check, if the value in firebase has "" is an String type and in your POJO you should have a variable with the type String for what you are trying to access, but if the value dosnt have "" it should be a long , int, double or any type of number.
EDIT: check this structure
It has all the values types as String, but in your Family.class you have the values right for this type of structure.
you should change your database at firebase so all your types matches with the ones in your Family.class, either way it won't fetch your values
Note: if you want to fetch all your values like they are at the first image, just change in Family.class from this:
int id;
String name;
String fatherName;
int fid;
String city;
String state;
to this:
String id;
String name;
String fatherName;
String fid;
String city;
String state;
Also change your constructor types and everything to match all Strings
The thing is that firebase creates unique IDs for each element in your database structure, and the types imported from your MySQL database are not the same as the firebase ones, I suggest you to either change your Family.class variable types as I mentioned above, or replicate your MySQL database with firebase and the same variable types.
This is happening because you have a variable of integer datatype in your model but you are returning String from Firebase... either convert your variable to string or return integer from firebase....
Both model and Firebase variable should be of a same data type.
As per your below error:-
com.google.firebase.database.DatabaseException: Failed to convert a value of type java.lang.String to int at com.google.android.gms.internal.firebase_database.zzkt.zzb(Unknown Source:180)
I think, you need to check somewhere you tried to store value in int which is store in firebase in string.
So first check it and if necessary to cast then casting your value using Integer.parseInt or Integer.valueof
for example,
Integer.valueOf(dataSnapShot.getValue());
or
Integer.parseInt(dataSnapShot.getValue());
For more understanding this you can also refer stack overflow's below links:
Firebase DatabaseException: Failed to convert value of type java.lang.Long to String
com.google.firebase.database.DatabaseException: Failed to convert a value of type java.lang.String to double
Firebase android error "Failed to convert value of type "

ORMlite how to add Collection<Collection<Double>>?

I have the following Class:
#DatabaseTable
public class BodyWeight implements Serializable {
#DatabaseField(generatedId = true, useGetSet = true, columnName = "id")
private Long id;
#DatabaseField
private String name;
#DatabaseField
private double goal;
#DatabaseField
private String primaryunit;
#DatabaseField
private String secondaryunit;
#DatabaseField
private int secondarysize;
#DatabaseField
private Collection<Collection<Double>> data;
How could I add a list of list of doubles primitives to database? What is the process? Should I create more classes for the List of list of doubles?
One possible way would be to keep Collection<Collection<Double>> data in your class and store it as JSON string in database with using custom persister. Like this
#DatabaseField(persisterClass = MyCustomPersister.class)
Collection<Collection<Double>> data;
Where MyCustomPersister should implement com.j256.ormlite.field.DataPersister or one of available implementations. Basically just two methods:
#Override
public Object resultToSqlArg();
#Override
public Object sqlArgToJava();
How could I add a list of list of doubles primitives to database? What is the process?
This is pretty complex. One way is just to make the type be serializable.
#DatabaseField(dataType = DataType.SERIALIZABLE)
private Collection<Collection<Double>> data;
That, like #unnamed_b's answer will store it in place as a serialized block of bytes. This won't work if you have a large number of doubles however.
If you want to store it as objects in another table then you are going to have to define these objects. Something like:
#DatabaseField(generatedId = true)
private long id;
#ForeignCollectionField
private Collection<DoubleCollection> data;
ORMLite only handles straight collections so we need to define the sub-collection:
#DatabaseTable
public class DoubleCollection {
#DatabaseField(generatedId = true)
private long id;
#ForeignCollectionField
private Collection<DoubleWrapper> data;
}
If you need to store a collection of doubles then you need to define a wrapper to hold an id and your double value.
#DatabaseTable
public class DoubleWrapper {
#DatabaseField(generatedId = true)
private long id;
#DatabaseField
private double value;
}

Realm query with List

I'm using realm to store my data on Android. Awesome framework! Now the only problem I'm now having is:
I got a array list strings with id's of Countries in my database.
Now I retrieve my Drinks that contains a relationship to countries.
Is there a way that I could to do a query like this:
String [] ids;
realm.where(Drinks.class).equalsTo("country.id", ids);
Something like that?
Or do I really need to do a query to get me all drinks and then filter the list manually?
EDIT:
My classes:
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private Country country;
}
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
}
What you want to do is possible with link queries in theory (searching for "country.id"), however link queries are slow. Also you'd need to concatenate a bunch of or() predicates together, and I would not risk that with a link query.
I would recommend using the following
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private Country country;
#Index
private String countryId;
}
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
}
And when you set the Country in your class, you also set the countryId as country.getId().
Once you do that, you can construct such:
RealmQuery<Drinks> drinkQuery = realm.where(Drinks.class);
int i = 0;
for(String id : ids) {
if(i != 0) {
drinkQuery = drinkQuery.or();
}
drinkQuery = drinkQuery.equalTo("countryId", id);
i++;
}
return drinkQuery.findAll();
Since the Realm database has added RealmQuery.in() with the version 1.2.0
I suggest using something like this.
//Drinks
public class Drinks extends RealmObject {
#PrimaryKey
private String id;
private String name;
private String countryId;
//getter and setter methods
}
//Country
public class Country extends RealmObject {
#PrimaryKey
private String id;
private String name;
//getter and setter methods
}
The code to use inside activity/fragments to retrieve drink list
String[] countryIdArray = new String[] {"1","2","3"} //your string array
RealmQuery<Drinks> realmQuery = realm.where(Drinks.class)
.in("countryId",countryIdArray);
RealmResults<Drinks> drinkList = realmQuery.findAll();
In latest version of Realm 7+, you can use anyOf to match a field against a list of values.
anyOf("name", new String[]{"Jill", "William", "Trillian"})
in older versions, use in instead of anyOf and with kotlin use oneOf instead of in.
see this issue
To match a field against a list of values, use in. For example, to find the names “Jill,” “William,” or “Trillian”, you can use in("name", new String[]{"Jill", "William", "Trillian"}). The in predicate is applicable to strings, binary data, and numeric fields (including dates).
Doc.-> https://realm.io/docs/java/latest#queries

Manually updating a foreign key.

I am pretty much aware of the absence of foreign keys in Realm. But I encountered this issue. I receive data in a normalised way and I have to figure out how to properly persist the relations.
Example:
class User{
private int id;
private Email email;
}
class Email{
private int id;
private String address;
}
And I receive something like:
{user={id:1, emailId:1}}
How can I store this type of data in my existing realm object ?
You will have to parse the JSON yourself to setup the links. From your description it isn't clear if you User and Email is already in Realm, but if that is the case I would do something like this:
class User{
#PrimaryKey
private int id;
private Email email;
}
class Email{
#PrimaryKey
private int id;
private String address;
}
JSONObject json = new JSONObject("{id:1, emailId:1}");
realm.beginTransaction();
User user = realm.where(User.class).equalTo("id", json.getInt("id")).findFirst();
Email email = realm.where(Email.class).equalTo("id", json.getInt("emailId")).findFirst();
user.setEmail(email);
realm.commitTransaction();

android: cache gson data in sqlite database

I want to use a local sqlite database to cache all gson objects. Therefore I created some Gson classes like this one:
package com.getbro.bro.Json;
import com.google.gson.annotations.SerializedName;
public class User extends Item {
public User(String Sex, String UserName, String[] Followed){
this.Sex = Sex;
this.UserName = UserName;
this.Followed = Followed;
}
#SerializedName("sex")
public String Sex;
#SerializedName("username")
public String UserName;
#SerializedName("followed")
public String[] Followed;
#Override
public String toString() {
return UserName;
}
}
Now I want to use this class as Sugar ORM model, but then, I have to rewrite the constructor to something like this:
public User(Context c, String Sex, String UserName, String[] Followed){
this.Sex = Sex;
this.UserName = UserName;
this.Followed = Followed;
}
How can I get Gson to use this "special" constructor and select the wright context?
With 1.3 release, sugar doesn't require a Context parameter in the constructor. So, it makes easy for Gson classes to use Sugar.
Specifically with Gson, you could use their custom serializers in case you don't have the default constructor. More details here.. https://sites.google.com/site/gson/gson-user-guide#TOC-Custom-Serialization-and-Deserialization

Categories

Resources