I am using mvp Design pattern in android development and i am using retrofit2 with it ... when i run the function to get me information from a the web it get the information but returns null list
the Response.Body come with response that mean that the code works
the model function
List<SearchDdb> searchResult;
private Context context;
public MainModel(Context context){this.context=context;}
public List<SearchDdb> searchUser(String name) {
final MainPresenter presenter = new MainPresenter(context);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
Db db = retrofit.create(Db.class);
Call<List<SearchDdb>> call = db.getUsers(name);
call.enqueue(new Callback<List<SearchDdb>>() {
#Override
public void onResponse(Call<List<SearchDdb>> call, Response<List<SearchDdb>> response) {
if(!response.isSuccessful()){
presenter.showDialog();
}
searchResult = response.body();
}
#Override
public void onFailure(Call<List<SearchDdb>> call, Throwable t) {
}
});
return searchResult;
}
the SearchDdb file
private int id;
private String name;
private String grade;
private String age;
private String address;
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getGrade() {
return grade;
}
public String getAge() {
return age;
}
public String getAddress() {
return address;
}
}
How i call the function
List<SearchDdb> ressult = presenter.searchUser("1");
You cant call it like List<SearchDdb> ressult = presenter.searchUser("1"); because searchUser method makes an async request via retrofit. This way searchUse returns null searchResult because response has not come yet.
Define a LiveData in your viewmodel class and observe it in your activity/fragment. When response comes from api in
onResponse in searchUser post that response to live data and use it where you observe.
If you want to see a tutorial you can look at this article.
Here is another example.
Related
I have a problem with Retrofit. I am working on an Android app which needs to get information about a product from Open Food Facts API. I tried with Retrofit, I created a class with the information I want from JSON (I only need a few fields and I didn't want to make a class with all the JSON fields, because there are over 50 I think)
public class Product {
#SerializedName("product_name_en")
private String name;
#SerializedName("brands")
private String company;
#SerializedName("update_key")
private int key;
public String getName() {
return name;
}
public String getCompany() {
return company;
}
public int getKey() {
return key;
}
}
Then I created an interface with the #GET method and the relative URL to the API endpoint
public interface OpenFoodFactsAPI {
#Headers("User-Agent: Fooducate - Android - Version 1.0")
#GET("/api/v0/product/01223004")
Call<Product> getProducts();
}
And inside my fragment I did this
TextView text = view.findViewById(R.id.txt);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://us.openfoodfacts.org")
.addConverterFactory(GsonConverterFactory.create())
.build();
OpenFoodFactsAPI jsonPlaceHolderApi = retrofit.create(OpenFoodFactsAPI.class);
Call<Product> call = jsonPlaceHolderApi.getProducts();
call.enqueue(new Callback<Product>() {
#Override
public void onResponse(Call<Product> call, Response<Product> response) {
if (!response.isSuccessful()) {
text.setText("Code: " + response.code());
return;
}
Product product = response.body();
String content = "";
content += "NAME: " + product.getName() + "\n";
content += "COMPANY: " + product.getCompany() + "\n";
content += "KEY: " + product.getKey() + "\n";
text.append(content);
}
#Override
public void onFailure(Call<Product> call, Throwable t) {
text.setText(t.getMessage());
}
});
I tried the get request on a website and it works. However, in my app an empty response is returned.
You can view the JSON from the api here
If you have any idea about this problem, please answer. Thank you!
From the API you are not getting exactly the Product as response. You are getting another object which is Product is a child object.
You need to create a response Like below,
public class ResponseObject{
#SerializedName("status")
private int status;
#SerializedName("status_verbose")
private String status_verbose;
#SerializedName("product")
private Product product;
//getters and setters goes here
}
then your interface should be like below as you are expecting ResponseObject here.
public interface OpenFoodFactsAPI {
#Headers("User-Agent: Fooducate - Android - Version 1.0")
#GET("/api/v0/product/01223004")
Call<ResponseObject> getProducts();
}
This will solve your problem. Update me If you have any problem with this.
After using
public class ResponseObject{
#SerializedName("status")
private int status;
#SerializedName("status_verbose")
private String status_verbose;
#SerializedName("product")
private Product product;
}
Just change
public int getKey() {return key;}
to
public String getKey() {
return key;
}
Otherwise
Error: java.lang.NumberFormatException: For input string: "ecoscore20210127"
because in json it exists like "update_key": "ecoscore20210127"
I'm using Retrofit to make API call, When I handle the response I get an error, I'm trying to get data from this API call on this page https://my-json-server.typicode.com/jayraic/demo/db
Attempt to invoke interface method 'java.lang.Object java.util.List.get(int)' on a null object reference
Retrofit base call
public class NBADataFactory {
private final static String BASE_URL = "https://my-json-server.typicode.com/jayraic/demo/";
public final static String DB_URL = "https://my-json-server.typicode.com/jayraic/demo/db";
public static NBAService create() {
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit.create(NBAService.class);
}
Retrofit Call
private void fetchTeamList() {
NBAApplication nbaApplication = NBAApplication.create(context);
NBAService nbaService = nbaApplication.getNbaService();
Disposable disposable = nbaService.fetchTeam(NBADataFactory.DB_URL)
.subscribeOn(nbaApplication.subscribeScheduler())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<NBAResponse>() {
#Override
public void accept(NBAResponse nbaResponse) {
changeTeamDataSet(nbaResponse.getTeamList());
teamProgress.set(View.GONE);
teamLabel.set(View.GONE);
teamRecycler.set(View.VISIBLE);
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) {
messageLabel.set(context.getString(R.string.error_loading_people));
teamProgress.set(View.GONE);
teamLabel.set(View.VISIBLE);
teamRecycler.set(View.GONE);
}
});
compositeDisposable.add(disposable);
}
private void changeTeamDataSet(List<Team> teams) {
teamList.addAll(teams);
setChanged();
notifyObservers();
}
Response Model
public class NBAResponse {
List<Team> teamList;
public List<Team> getTeamList() {
return teamList;
}
}
Team Model
public class Team implements Serializable {
#SerializedName("id") public String id;
#SerializedName("full_name") public String full_name;
#SerializedName("win") public String win;
#SerializedName("losses") public String losses;
#SerializedName("players") public List<Player> players;
}
I'm trying this out and stuck at this issue, any help or direction to right path would be appreciated.
The response json has teams as outer array name, but in your response Pojo class has its name teamList. Either of below should solve your problem
List<Team> teams;
or
#SerializedName("teams")
List<Team> teamList;
The GET request to tenants/client/{hostname} returns a json object with the property baseApiHostname.
#GET("api/tenants/client/{hostname}")
Call<HostName> getHostname(#Path("hostname") String hostname);
baseApiHostname is successful retrieved. That hostname which is used to create the rest of tenant requests from.
Log.v("base url","testing "+preferenceManager.getTenantHostname());
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(builder.create()))
.baseUrl(preferenceManager.getTenantHostname())
.build();
I received the error "java.lang.IllegalArgumentException: Illegal URL".
stacktrace message
After attaching debugger I realized that hostname = null.
debugger message
Call<HostName> call = hostNameApiService.getHostname(tenant);
call.enqueue(new Callback<HostName>() {
#Override
public void onResponse(Call<HostName> call, Response<HostName> response) {
if (response.isSuccessful()) {
String hostname = response.body().getBaseApiHostname();
preferenceManager.setTenantHostname(hostname);
retrieveCampaign();
} else {
Toast.makeText(StartSurveyActivity.this, "Error Retrieving Hostname", Toast.LENGTH_SHORT).show();
}
}
Here is the Hostname model class
#SerializedName("id")
private String id;
#SerializedName("name")
private String name;
#SerializedName("baseApiHostName")
private String baseApiHostname;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBaseApiHostname() {
return baseApiHostname;
}
public void setBaseApiHostname(String baseApiHostname) {
this.baseApiHostname = baseApiHostname;
}
If there's any other detail required that will aid in helping myself and other developers who may have faced a similar problem, please don't hesistate to ask.
Thanks in advance guys.
GSON is not successfully serializing any response to the field you're retrieving, so there is some misalign in how you are setting up gson to parse your json result.
Given your object and your sample JSON, your field in JSON is "baseApiHostname" whereas in your object your GSON annotation is for serialized name "baseApiHostName".
You are setting null in your Retrofit.Builder for your base URL. What is the URL for your server? You need to set that for the first time. Then you can change it after that if need be but it can't be null the first time.
I'm using Retrofit to send picture request and receive this Json
{"response":{
"face":{
"value":"true",
"confidence":55
},
"gender":{
"value":"male",
"confidence":73
},
...
}}
and I'm receiving it with Retrofit....
RestAdapter adapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(END_POINT)
.build();
Mylistenerr listener = adapter.create(Mylistenerr.class);
File photo = new File(picturePath);
TypedFile image = new TypedFile("multipart/image/jpg", photo);
listener.setUserImage(
image,
new Callback<respostring>() {
#Override
public void success(respostring rp, Response arg1) {}
#Override
public void failure(RetrofitError arg0) {
pd.hide();
pd.dismiss();
Log.d("ERROR:", arg0.getLocalizedMessage());
}
});
}
private static class respostring {
private Content face;
private Content gender;
respostring() {}
}
class Content
{
private int confidence;
private String value;
Content(){}
public int getconf(){
return this.confidence;
}
public String getvalue(){
return this.value;
}
}
My interface
public interface Mylistenerr {
#Multipart
#POST("/public/test")
void setUserImage(
#Part("image") TypedFile file,
Callback<respostring> response);
}
but there is retrofit error. Is there something I miss here?
I'd recommend you using Gson for json deserialization instead since retrofit supports it very well. Then you can just create classes like this:
Your face class:
public class Face implements Serializable {
#SerializedName("value")
public boolean value;
#SerializedName("confidence")
public int confidence;
}
Your gender class:
public class Gender implements Serializable {
#SerializedName("value")
public String value;
#SerializedName("confidence")
public int confidence;
}
your response class:
public class YourResponseType implements Serializable {
#SerializedName("face")
public Face face;
#SerializedName("gender")
public Gender gender;
}
Then you can actually make retrofit doing the rest for you:
listener.setUserImage(image, new Callback<YourResonseType>() {...});
Hope that helps!
I solved the problem.
I was sending plain-text in the server.
Changed the line to read:
response.writeHead(200, {'Content-Type': 'application/json'});
Quick question. My friend recommended looking into Retrofit rather than using my ASync task for my REST android application. I am having one small problem since I am new to the system. The server runs using Node.js to send JSON objects by means of .stringify() and so when I retrieve an object it is a String rather than a JSON, and I cannot convert it to my List of the appropriate objects. I am guessing the error is due to a cast exception because it is sending a string because I get the exception:
com.google.gson.JsonSyntaxException
Any help would be great. Here is the code I thought would be appropriate.
Android Client Code Example below:
private void requestData() {
RestAdapter adapter = new RestAdapter.Builder().setEndpoint(ENDPOINT).build();
UnitAPI unit_api = adapter.create(UnitAPI.class);
unit_api.getUnits(new Callback<List<Unit>>() {
#Override
public void success(List<Unit> t, Response response) {
units = t;
updateDisplay();
}
#Override
public void failure(RetrofitError error) {
Log.d("Failure UnitGet()", error.getMessage());
}
});
}
Android Unit.class:
public class Unit {
private String ID;
private long bearing;
private long lat;
private long lng;
private String type;
public String getID() {
return ID;
}
public void setID(String ID){
this.ID = ID;
}
public long getBearing() {
return bearing;
}
public void setBearing(long bearing){
this.bearing = bearing;
}
public void setLat(long lat){
this.lat = lat;
}
public long getLat(){
return lat;
}
public void setLng(long lng){
this.lng = lng;
}
public long getLng(){
return lng;
}
public void setType(String type){
this.type = type;
}
public String getType(){
return type;
}
}
The server sends the .json file via the command:
if (method == "GET") {
response.write(JSON.stringify(unitsJSON));
}
Any thoughts on how I can convert it to a list of units from the string on the client side or a json object on the server side?
Thanks!
I solved the problem. I was sending plain-text in the server. Changed the line to read:
response.writeHead(200, {'Content-Type': 'application/json'});
I think you must add json-parser to package using npm
then
in response write
res.end(JSON.stringfy('your resp0onse here'));