Assuming i have this dummy API
#POST("somepath/setSomething")
Call<ExecuteResponse> setSomething(#Body ExecuteInput input);
and this callBack
Callback<ExecuteResponse> callBack = new Callback<ExecuteResponse>() {
#Override
public void onResponse(Call<ExecuteResponse> call, Response<ExecuteResponse> response) {};
How can i access the body of the call and getting back my ExecuteInput Object?
You can do response.getBody() and you will get the object you specified inside Response<???>. In this case, ExecuteResponse.
Of course, I'm supposing you have defined the #SerializedName inside your object or that you have the right field names inside the ExecuteResponse model class.
Related
I'm trying to use retrofit for get records from my API and it works fine when i do something like this.
public interface materialAPI {
#GET("/mlearningServices/Course")
public void getMaterials(Callback<List<materialClass>> response); } public void getMaterials()
{
RestAdapter adapter = new RestAdapter.Builder().setEndpoint(Root_Url).build();
Log.i(TAG , "hERE IS THE LINK"+adapter.toString());
materialAPI api = adapter.create(materialAPI.class);
api.getMaterials(new Callback <List<materialClass>>() {
#Override
public void success(List<materialClass> list, Response response) {
materials = list;
showList();
customAdapter customAdapter = new customAdapter();
listView.setAdapter(customAdapter);
}
#Override
public void failure(RetrofitError error) {
}
});
}
The above code works fine and i can get all my materials but what i want to achieve next is get material with any id . When a user selects a paticular material, i want to pass the id into the get url so i can get the records
meaning i have to do something like this
#GET("/mlearningServices/Course/{myId}")
..
How to i add myId to the callback method. This is my first time of using retrofit
Use the #Path annotation
#POST("/mlearningServices/Course/{myId}")
public void getMaterials(#Path("myId") String id, Callback<Response> response);
References:
https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/Path.html
http://square.github.io/retrofit/
That you are asking about is called a path variable. To set one, you must rewrite your method signature as this:
public void getMaterials(#Path("myId") String id, Callback<List<materialClass>> response);
This way, the variable defined as /path/to/your/endpoint/{nameOfPathVariable} will be injected into that String parameter passed to the method. You could also define it as an Integer, and retrofit will try to cast it accordingly.
Solution:
You can use this to pass your id, Use the #Path annotation
#GET("/mlearningServices/Course/{myId}")
Call<materialClass> getMaterials(#Path("myId") String id);
#Path is some data that you wish to provide it to GET method before Question Mark ("?") and #Query("..") is some data you wish to provide after "?"
Hope you have understood.
In my andorid app I am making a GET request using Retrofit2:
http://myapi.com/items/list
But I would also like to make another request e.g.
http://myapi.com/items/list/filter/active:true,min_price:100
So the filter parameter is optional. I am trying to do the following:
#GET("items/items/list{filter}")
Observable<ResponseItems> getItems(#Path("filter") String filter);
and calling it like:
service.getItems("")
and:
service.getItems("/filter/active:true,min_price:100")
But it does not work. So I ended up creating two separate service calls, one with filter param and other without. I think that there should be more elegant method though.
So i've seen what you are trying to achieve.
How your api declaration should looks like:
#GET("items/list/{filter}")
Observable<ResponseItems> getItems(#Path(value = "filter", encoded = true) String filter);
and a call service.getItems("") would lead to http://myapi.com/items/list/ be called
a call service.getItems("filter/active:true,min_price:100") would lead to
http://myapi.com/items/list/filter/active:true,min_price:100 be called.
An encoded property in #Path annotation is set because your optional path parameter contains / and retrofit encodes it without that property.
So as i wrote in comments better use two declarations:
#GET("items/list/")
Observable<ResponseItems> getItems();
#GET("items/list/filter/{filter}")
Observable<ResponseItems> getItems(#Path(value = "filter") String filter);
so you may call it like service.getItems("active:true,min_price:100")
In simple word make method over loading. Create two method with same name and different parameter. Check my below source code. (written in kotlin)
#GET("myportal/news/{id}")
fun getNewsList(#Path("id") id: String): Call<NewsEntity>
#GET("myportal/news/{id}/{dateTime}")
fun getNewsList(#Path("id") id: Long, #Path("dateTime") dateTime: String): Call<NewsEntity>
Its better to use HashMap to send optional params in a request, this allows you to send single/multiple optional params in your request also if you send the HashMap empty it will not affect your request.
Your interface will contain code like snippet below
#POST("yourUrl")
#FormUrlEncoded
Call<YourResponse> yourApiRequest(#Header("Authorization") String token,
#Field("mandatoryParam") int mandatoryParam,
#FieldMap Map<String, String> optionalParamMap);
And your API call will be something like the following
private HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("optionalParam1", value1);
hashMap.put("optionalParam2", value2);
ApiClient.getApiClient().getApiInterface().yourApiRequest(token,
mandatoryParam, hashMap)
.enqueue(new Callback<YourResponse>() {
#Override
public void onResponse(Call<YourResponse> call, Response<YourResponse> response) {
}
#Override
public void onFailure(Call<YourResponse> call, Throwable t) {
}
});
In a case where you don't want to send any optional params you can pass an empty hashmap to your request.
I am using Retrofit to Post form data and recieve back XML. What I have so far works fine but i want to make some changes. Here is my existing code (and it works):
Here is my interface
public interface SignupUser
{
#FormUrlEncoded
#POST("/createaccount.cfm")
SignupServerResponse signup(#Field("e") String email, #Field("p") String password);
}
Here is the code to call the api (again, this works fine, I will explain below what I want to change)
SignUpDetails mDeets; // this gets initialize and set somewhere else
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint("http://myurl.com")
.setConverter(new SimpleXMLConverter()).build(); // the response is xml, that works fine
SignupUser service = restAdapter.create(SignupUser.class);
SignupServerResponse res = service.signup(mDeets.getE(), mDeets.getP());
How can I make it so that I can pass the SignUpDetails object straight to the signup() method instead of passing in separate Strings? When I change the constructor of signup() to accept SignUpdetails object (see below) and pass my SignUpDetails object in, I get an error saying
No Retrofit Annotation Found
Here is how I would like to define the interface
public interface SignupUser
{
#FormUrlEncoded
#POST("/createaccount.cfm")
SignupServerResponse signup(SignUpDetails deets);
}
And call it like this (instead of passing in all those parameters)
SignupServerResponse res = service.signup(mDeets);
I tried adding #Field above each of my variables in the SignUpDetails class and that doesnt work either (compilation error)
On your interface use #Body annotation for the deets parameter:
#POST("/createaccount.cfm")
SignupServerResponse signup(#Body SignUpDetails deets);
That should convert SignUpDetails into XML (since you use xml converter on your adapter).
It is then your responsibility to parse the XML request body on server.
Using Retrofit for Android I'm successfully connecting to a web service with a login and password:
getService().doSignIn( m_editEmail.getText().toString(), m_editPwd.getText().toString(),new Callback<Object>() {
#Override
public void success(Object login, Response response) {
}
#Override
public void failure(RetrofitError error) {
}
});
You may ask why am I using Object and not a class? Well, I could not get any return data unless I used the generic Object class. I tried to create a class with the property names I expected to get back but couldn't get it to work (just empty values for the class's properties would be returned).
So now when I use Object I get data back but its in the LinkedTreeMap type like this:
root // this is of type com.google.json.internal.LinkedTreeMap
[0]
key
value // this is of type com.google.json.internal.LinkedTreeMap
[0] REsult Code - > 0
[1] Result Message -> success
[2] ...
So basically it is returning a LinkedTreeMap within a LinkedTreeMap ---How can I map this to a class with matching properties for easier retrieval?
I'm using retrofit for fetching data from resource. But think my architecture is wrong.
So, i have an fragment with listview, for example.
In onCreateView after UI setup i calls API method(async). That returns list of models i need to setup my listview adapter.
Thats i do in callback
private Callback<List<User>> mUsersCallback = new Callback<List<User>>() {
#Override
public void success(List<User> users, Response response) {
mLoadingLayout.hideLoading();
mPeopleAdapter = new PeopleAdapter(getActivity(), users);
lvPeople.setAdapter(mPeopleAdapter);
}
#Override
public void failure(RetrofitError error) {
mLoadingLayout.hideLoading();
Log.d("get users", error.getUrl() + " " + error.toString());
}
};
In this part i sometimes get NPE when call getActivity();
How to do it on right way?
Your activity has been destroyed during the call, when you try to get it in your callback, it may be null.
Simply check if activity is not null and if null ignore the callback.
Try to create your own Callback class and there pass your Activity or Context by constructor.
Similar to this answer: https://stackoverflow.com/a/25665521/2399340