I have retrieve data from Server using Retrofit and now I am trying to store with sqlite database
WebserviceHandler.getImagePathSelectAl()
.subscribeOn(Schedulers.io())
.flatMap(s -> WebserviceHandler.getCtbLeidSource())
.subscribeOn(Schedulers.io())
.subscribe(.................);
and response model class like
public class ImagePathResponse {
#SerializedName("Message")
#Expose
private String message;
#SerializedName("HasColumns")
#Expose
private Integer hasColumns;
#SerializedName("ErrorMessage")
#Expose
private String errorMessage;
#SerializedName("ImagePath_insert")
#Expose
private List<ImagePath> imagePathInsert = null;
#SerializedName("ImagePath_update")
#Expose
private List<ImagePath> imagePathUpdate = null;
and
public class LeedSourceResponse {
#SerializedName("Message")
#Expose
private String message;
#SerializedName("HasColumns")
#Expose
private Integer hasColumns;
#SerializedName("ErrorMessage")
#Expose
private String errorMessage;
#SerializedName("LeedSource_insert")
#Expose
private List<LeedSource> leedSourceInsert = null;
#SerializedName("LeedSource_update")
#Expose
private List<LeedSource> leedSourceUpdate = null;
now i want to insert and update sqlite db in each response, how can achieve this. I am new to RxJava and RxAndroid
You can check Rooms persistence library its a sql library for androidRooms , but in this case I would recommend you using RealmDb instead of sql, its much faster and would work perfectly if you want to save your date for every response.
Related
Room does not work on android api 28.
I get this error: no such table: user (code 1 SQLITE_ERROR):, while compiling: select * from user
On the other versions, the db works fine. what could be the problem?
def room_version = "1.1.1"
implementation "android.arch.persistence.room:runtime:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:$room_version"
implementation "android.arch.persistence.room:rxjava2:$room_version"
User entity:
#Entity(tableName = "user")
public class User {
#SerializedName("user_id")
#PrimaryKey
private long userId;
#SerializedName("created_at")
private String createdAt;
#Expose
private String lastLogin;
#SerializedName("login_count")
private Integer loginCount;
#Expose
#Embedded
private UserProperties properties;
#IgnoreJson
private long localUpdatedAt;
#SerializedName("updated_at")
private String updatedAt;
I am using Retrofit2 to send and receive requests to my server.
Here are my API interface and Model class.
Interface
public interface ApiInterface {
#POST("/users/")
Call<User> signUp(#Body User user);
#POST("/login_url/")
Call<User> login(#Body User user);
}
Retrofit client
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getRestClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
POJO class
public class User {
#SerializedName("id")
private Integer id;
#SerializedName("email")
#Expose
private String email;
#SerializedName("first_name")
private String firstName;
#SerializedName("last_name")
private String lastName;
#SerializedName("password")
#Expose
private String password;
}
I have exposed email and password so that in login request these 2 parameters will be added.
But for another request like Sign up, I required a first name and last name also to be sent along with email and password.
Can I use same "User" class for both ? because if I expose the first name and last name then, those fields will be also sent in login request.
Is there any other way or should I make different POJO classes for both request ?
Instead of sending the whole class , you can use #Field annotation , so your login callback will be something like this :
#FormUrlEncoded
#POST("/login_url/")
Call<User> login(#field("email")String email,#field("password")String password);
#FormUrlEncoded denotes that the request body will use form URL encoding. Fields should be declared as parameters and annotated with #Field.
Can I use same "User" class for both ?
Yes , you can use the same Model as #Body for both requests !
Just make sure where you don't need the required variables just omit them !!
Remove the #SerializedName and #Expose , these are not required and give the variable names according to the json KEYs
public class User {
private Integer id;
private String email;
private String firstName;
private String lastName;
private String password;
}
Edit
Suppose for example , for one request you need :-
4 params you set the model user as
new User(id,email,firstname,lastname); // dont init the password attribute
5 params you set all values to the model like
new User(id,email,firstname,lastname,password);
I am using retrofit w/ gson annotations to bind my incoming JSON to a model and its member attributes to types like String, int, float, etc...
public class Location {
#SerializedName("user_id")
#Expose
private int userId;
But how do I bind to a member variable that's of type JSON? I want it to be unstructured which is why I can't just map it to a well-defined model.
#SerializedName("metadata")
#Expose
private JsonObject metadata;
How do I get the above to work?
Looks like I can set the member attribute to JsonElement
#SerializedName("metadata")
#Expose
private JsonElement metadata;
This resolves the issue of binding to JsonNull + JsonObject.
I am using Retrofit to send and receive requests to my server.
I Have a model like below and I have to send it to my server but some variables in this model have not to send to the server.
public class SelectedListModel implements Serializable {
#SerializedName("p_id")
#Expose
private Long pId;
#SerializedName("p_qty")
#Expose
private Double pQty;
#Expose(serialize = false , deserialize = false)
private String pName; //Have not to send to server
#Expose(serialize = false , deserialize = false)
private String pPrice; //Have not to send to server
#Expose(serialize = false , deserialize = false)
private String pImageUrl; //Have not to send to server
}
and because of that, I am getting 400 in my responses from the server.
I used of #Expose(serialize = false, deserialize = false) in order to Ignore variables that have not to send to the server.
But it doesn't work.
Is there any way to do this or I have to create another model just for my server?
Use transient keywork for that
public class SelectedListModel implements Serializable {
#SerializedName("p_id")
#Expose
private Long pId;
#SerializedName("p_qty")
#Expose
private Double pQty;
//#Expose(serialize = false , deserialize = false)
private transient String pName; //Have not to send to server
//#Expose(serialize = false , deserialize = false)
private transient String pPrice; //Have not to send to server
//#Expose(serialize = false , deserialize = false)
private transient String pImageUrl; //Have not to send to server
}
and no need to use #Expose(serialize = false , deserialize = false), into those fields which needed to be excluded.
Read Why does Java have transient fields? and Why use the `transient` keyword in java? for more details.
You can use transient keyword to ignore fields when requesting api calls
JAVA:
transient String name;
KOTLIN:
#Transient
var name: String
change your Retrofit adapter code like this (I hope you're using retrofit2)
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
I'm working on API Requests with Retrofit(1.9.0) and gson library (1.7.0 I have compatibility issues with version 2.3.1 of gson) on Android, I make some request to an API which have same format of response but different content following the url call, but I encounter a problem for a deserialization of one answer which there is array inside. This is an example of the json I want to deserialize :
{
"http_code":200,
"content":[
{
"name":"Groult Christian",
"location":[
48.897655,
2.252462
],
"website":null,
"address":{
"street_address":"XXXXXX",
"city":"XXXXXX",
"state":null,
"postal_code":"XXXXXX",
"country":"XXXXXX"
},
"global_score":0,
"popularity_score":0,
"quality_score":0,
"createdAt":"2015-02-18T02:13:05.068Z",
"updatedAt":"2015-02-18T02:13:05.068Z",
"id":"54e3f531775288ca572872ac"
},
...
]
}
My DeserializerJson and how I call it for retrofit:
public class DeserializerJson<T> implements JsonDeserializer<T> {
#Override
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)
throws JsonParseException
{
// Get the "content" element from the parsed JSON
JsonElement content = je.getAsJsonObject().get("content");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
return new Gson().fromJson(content, type);
}
}
...
Gson gson = new GsonBuilder()
.registerTypeAdapter(ContentUser.class, new DeserializerJson<ContentUser>())
.registerTypeAdapter(DeviceInfo.class, new DeserializerJson<DeviceInfo>())
.registerTypeAdapter(PlacesModel.class, new DeserializerJson<PlacesModel>())
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.BASIC)
.setConverter(new GsonConverter(gson))
...
...
and my different models:
public class PlacesModel {
#SerializedName("name")
#Expose
private String name;
#SerializedName("location")
#Expose
private List<Double> location = new ArrayList<Double>();
#SerializedName("website")
#Expose
private Object website;
#SerializedName("address")
#Expose
private AddressModel address;
#SerializedName("global_score")
#Expose
private Integer globalScore;
#SerializedName("popularity_score")
#Expose
private Integer popularityScore;
#SerializedName("quality_score")
#Expose
private Integer qualityScore;
#SerializedName("createdAt")
#Expose
private String createdAt;
#SerializedName("updatedAt")
#Expose
private String updatedAt;
#Expose
#SerializedName("id")
private String id;
/* Getters and Setters... */
}
public class AddressModel {
#SerializedName("street_address")
#Expose
private String streetAddress;
#SerializedName("city")
#Expose
private String city;
#SerializedName("state")
#Expose
private Object state;
#SerializedName("postal_code")
private String postalCode;
#SerializedName("country")
#Expose
private String country;
/* Getters and Setters... */
}
url call in Api Manager is like this:
#GET("/places")
public void getPlaces(RestCallback<List<PlacesModel>> callback);
But when I do the call I get this error : com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#3b8aa06 failed to deserialize json object
Everything is fine for other call I get all content and so with no problem but one where there is array inside content I got an error and I don't understand why I believed if I just put a list of my model it will be fine but it doesn't work.
I think I miss something so if someone can help me
Thanks in advance
The problem of your issue is that you register DeserializerJson for PlacesModel class and in getPlaces method your response is List<PlacesModel> class. List<PlacesModel> is a different class as PlacesModelso Gson doesn't know how to deserialise List<PlacesModel>. What you have to do is register one more Deserialiser by this method:
.registerTypeAdapter(List.class, new DeserializerJson<List<PlacesModel>>())
If you use more than one type of List (I mean List<PlacesModel> and List< DeviceInfo >) You can define your own TypeAdapter or you cN change list to array and register deserialiser for them as is shown below
.registerTypeAdapter(PlacesModel[].class, new DeserializerJson<PlacesModel[]>())
Now everything works fine for yours json.