From my experimenting so far, it appears that Volley accesses its cache based on the URL alone. I would like to know if it also can determine which response it should return based on the combination of URL and request body data.
Is there a setting for this, or and extension point where I can implement this myself.
I don't see anywhere that the request body data is returned in the NetworkResponse object, or I would do the check in the parseNetworkResponse method.
Thanks
You have to override Request.getCacheKey() method to include request body as well, when implementing your custom request.
Related
I have an issue with load XML feed from url using Retrofit.
Given a dynamic url that clearly returns xml feed f.e: https://anchor.fm/s/53faae8/podcast/rss
When I try to load this via Retrofit I can see in Android Studio Network Profilier that it returns a scrambled response. Something like this:
ì½ÝvÜF’.z=ó5mÏ&d&€ÛmÊ’Ûš¶-K=š>{íµWH°`Ve EšsÕ÷çö¬5ûö
<X?ɉˆLüT‰jIUîÖL·šUäoDFdü|ñÙ?¯–Þ•iÚ²®~÷$8õŸx¦Ê꼬.~÷ä�o¾bêÉŸÖ´VíYžýîÉ¢ëÖgOŸ®7Íò´n.žæÙS³4+SuíÓà4xúÄ=›ÕU_¾û4úOWu¾Yšö©{pxQwõjxëúúúôZÐ{Ü÷ççðã“qȇl_+»MeÚ
Etc.
I've added an xml converter in my retrofitBuilder:
retrofitBuilder.addConverterFactory(SimpleXmlConverterFactory.createNonStrict(Persister(AnnotationStrategy())))
And my service code to retrieve the xml from url looks like:
interface XmlFeedService {
#GET
fun getXmlFeedFromUrl(#Url url: String): Call<RssFeed>
I am using #Url annotation here since the url is dynamic and depending what another api returns to me can result in urls with different base url's.
Of course the response body can't be parsed like this, but I am unclear why it comes back like this.
Can anyone help out?
Figured it out already.
It's not due to a wrong configuration of the Retrofit builder or the service, but the scrambled response that the Network Profiler showed me was due to the some of the Annotation in the Data models being wrongly configured...
I call a Rest API of salesforce by post method:
url = "https://test-dev-ed.my.salesforce.com/services/apexrest/AccountUsers/"
client = OkHttpClient()
val jsonIn = FormBody.Builder()
.add("email",URLEncoder.encode("dt1#gmail.com", "UTF-8"))
.add("password", URLEncoder.encode("1","UTF-8"))
.build()
request = Request.Builder()
.post(jsonIn)
.header("Authorization", "Bearer "+accesstoken)
.addHeader("Content-Type","application/x-www-form-urlencoded")
.url(url)
.build()
response = client.newCall(request).execute()
This is rest api:
#HttpPost
global static ID createUser(String email, String password) {
AccountUser__c us=new AccountUser__c();
us.Email__c=email;
us.Password__c=password;
us.Status__c=0;
insert us;
return us.Id;
}
But result return is error:
[{"errorCode":"UNSUPPORTED_MEDIA_TYPE","message":"Content-Type header specified in HTTP request is not supported: application/x-www-form-urlencoded"}]
I had try change application/json to application/x-www-form-urlencoded , but still can't resolve.
I try call a Get method, it is ok.
Why Post method occur error [Content-Type header specified in HTTP request is not supported]?
I would like to suggest a better resolution. Retrofit Library
Even though it is not mandatory to use Retrofit, these are few eye catchy aspects which makes it reliable and handy in similar use case of yours.
Why to use Retrofit?
Type-safe REST Adapter that makes common networking tasks easy
For POST operations, retrofit helps in assembling what needed to be submitted. Eg:- Generating URL encoded form.
Takes care of URL manipulation, requesting, loading, caching, threading, synchronization, sync/async calls
Helps to generate URL using type-aware generated code tied to specific REST API
Parsing JSON using GSON
Retrofit is an API adapter wrapped over OkHttp
The problem that you are facing can be resolved using retrofit like this.
public interface APIConfiguration{
#Headers({"Accept:application/json",
"Content-Type:application/x-www-form-urlencoded"})
#FormUrlEncoded
#POST("user/registration")
Observable<DataPojo> registrationAPI(#FieldMap(encoded = true) Map<String, String> params);
}
That's it, with few annotation the library takes care of Form URL
Encoding and related dependencies.
As it is inappropriate to start from corresponding Retrofit dependencies and sample code, you can go through Reference One and Reference Two for more details.
As per my understanding just checkout the difference the content type header "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.
The content "multipart/form-data" follows the rules of all multipart MIME data streams.
https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
Also try your http request by setting your content type header as multipart/formdata.
In my API server returns HTTP 400 response code if request does not pass validation, and provides detailed message, that should be parsed as the response.
For example:
public class RegistrationResponse {
private String emailError; // Detailed message. Null if no error occured
}
But Robospice (Retrofit + OkHttp) fires onRequestFailure() with message "retrofit.RetrofitError: 400 BAD REQUEST" in this case and, of course, does not parse anything.
How should I make it parse the response in case if response code is not 2XX?
You should declare Retrofit methods that return HTTP Response objects and check the raw object in your loadDataFromNetwork() for the status you need. This way, however, you will skip the out-of-the-box functionality of parsing responses and will have to do that manually.
Therefore, you should also find a way to reuse the Converter passed to your RestAdapter in the RetrofitSpiceService. Overriding the RetrofitSpiceService#createConverter() method is probably the simplest way to achieve this.
its my first time asking a question here, so please tell me if I missed to include something.
I have a method that prints returns a String. Inside it, is an asychronous volley request that retrieves a specific value to be added to the String. The problem is that the request is made, but since it's an asynchronous request, the method still proceeds and returns the String even if it still doesn't have the value from the request. The request completes afterwards. So the question is, is there a way to make the method wait for a specific variable to have a value before proceeding, without freezing the UI? Should I create a new thread instead?
Code below is not the actual codes I have but it shows the outline.
public String getStr{
StringBuilder sb = new StringBuilder();
String strOne;
// code here..
// asynchronous request here..
// code here..
sb.append(strOne)
// code here..
return sb.toString();
}
The asychronous request refers to the volley request.
Any help is appreciated. Thanks in advance!
You should handle the response in onResponse (#Override) method. Take a look in this tutorial:
Asynchronous HTTP Requests in Android Using Volley
If you want to return the response to another class to handle it there, I suggest you to implement an interface. I could post the code for this here, but I aswered a question like this here:
Volley , Wait for response to return wait until use flag - answer
I want to call http request using get method with passing json parameter to get request call.so what will be the proper way to call http get method with passing json request.
http://plaincodesource.blogspot.com/2010/10/android-post.html try this. I believe you can set reauest method "GET" and then write your json into output stream.