I just started porting from my existing network library to Android's Volley. So far I have successfully implemented Volleys ImageLoader where applicable. Now, I am trying to get my first http call up and running, but am finding this error.
Note: I intentionally started with a PATCH request because I will be using them frequently. Also, my version of Volley DOES support patch: https://android.googlesource.com/platform/frameworks/volley/+/master/src/com/android/volley/Request.java https://android.googlesource.com/platform/frameworks/volley/+/master/src/com/android/volley/toolbox/HurlStack.java
Stacktrace:
E/InputDialogFragment(27940): VolleyError: java.net.ProtocolException: Connection already established
D/Volley (27940): [1] MarkerLog.finish: (67 ms) [ ] https://mobile.example.com/m/api/v1/user/ 0xb33a3c8d NORMAL 2
D/Volley (27940): [1] MarkerLog.finish: (+0 ) [ 1] add-to-queue
D/Volley (27940): [1] MarkerLog.finish: (+0 ) [544] cache-queue-take
D/Volley (27940): [1] MarkerLog.finish: (+0 ) [544] cache-miss
D/Volley (27940): [1] MarkerLog.finish: (+0 ) [545] network-queue-take
D/Volley (27940): [1] MarkerLog.finish: (+14 ) [545] post-error
D/Volley (27940): [1] MarkerLog.finish: (+53 ) [ 1] done
PATCH Request
HashMap<String, Object> values = new HashMap<String, Object>();
values.put(mParam, val);
JsonObjectRequest request = new JsonObjectRequest(Request.Method.PATCH, APIConstants.URL_USER, new JSONObject(values),
new Response.Listener<JSONObject>(){
@Override
public void onResponse(JSONObject response){
// Blah do stuff here
mProgressDialog.dismiss();
}
},
new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error){
Log.e(TAG, "VolleyError: " + error.getMessage());
}
}){
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
VolleySingleton.getInstance().addCookie(headers);
return headers;
}
};
VolleySingleton.getInstance().getRequestQueue().add(request);
Yes, I plan to eventually build out classes for StringRequest, JsonObjectRequest, etc... but currently I just want to get one up and running.
Also, if you are wondering about addCookie, for now I prefer to save my cookie in preferences as I am not as familiar with CookieManager.
VolleySingleton
public class VolleySingleton {
private static final String COOKIE_KEY = "Cookie";
private static VolleySingleton mInstance = null;
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private SharedPreferences mPreferences;
private VolleySingleton(){
mRequestQueue = Volley.newRequestQueue(MyApplication.getAppContext());
mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
});
mPreferences = MyApplication.getAppContext().getSharedPreferences(PrefConstants.PREFERENCES, 0);
}
public static VolleySingleton getInstance(){
if(mInstance == null){
mInstance = new VolleySingleton();
}
return mInstance;
}
public RequestQueue getRequestQueue(){
return this.mRequestQueue;
}
public ImageLoader getImageLoader(){
return this.mImageLoader;
}
public final void addCookie(Map<String, String> headers) {
String cookie = mPreferences.getString(PrefConstants.PREF_COOKIE, null);
if(cookie != null){
headers.put(COOKIE_KEY, cookie);
}
}
}
Problem:
Volleys HurlStack (HttpUrlConnection) does have supporting code for PATCH. However, it appears to still throw the exception posted in my title and stacktrace whenever you try to issue a PATCH request.
Hack solution:
1) Force Volley to use HttpClientStack.
Below is an updated version of my VolleySingleton constructor. This 'works', but clearly wastes the Hurl implementation which is considered better if (Build.VERSION.SDK_INT >= 9). Not too mention Google plans to move on from the apache HttpClient altogether in future.
private VolleySingleton(){
mPreferences = MyApplication.getAppContext().getSharedPreferences(PrefConstants.PREFERENCES, 0);
String userAgent = "volley/0";
try {
String packageName = MyApplication.getAppContext().getPackageName();
PackageInfo info = MyApplication.getAppContext().getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {}
HttpStack httpStack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
mRequestQueue = Volley.newRequestQueue(MyApplication.getAppContext(), httpStack);
mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {
private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
});
}
2) Continue to use the above VolleySingleton ONLY for patch; rename it VolleySingletonPatch() and then of course create a Default VolleySingleton() for ALL other NON-PATCH calls. (better than 1, but still not optimal)
3) Solve the exception being thrown in HurlStack despite the fact that Volley has implemented PATCH. This would be BEST, but I prefer to avoid tinkering with Volley directly or extending my own HttpStacks unnecessarily.
I am leaving this unanswered as I would greatly appreciate any insight and of course better options than the ones I have come up with here.
I had this problem too, my solution was to just give up on the underlying inbuilt Apache HTTP components and use OkHttp library from Square using this HttpStack
implementation for Volley that uses OkHttp as its transport. Works great.
I know this question is old, but providing solution could help someone who is yet to encounter same challenge
JSONObject param = new JSONObject();
try {
param.put(KEY 1, VALUE 1);
param.put(KEY 2, VALUE 2);
} catch (JSONException e) {
e.printStackTrace();
}
//ID represents the id for the record to update
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.PATCH, YOUR URL+ "?ID=" + ID, param,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
//call handler to display response (optional)
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//call handler to display response (optional)
}
}) {
// Passing header
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=utf-8");
headers.put("x-api-key", "YOUR API KEY");
return headers;
}
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
//use this to check positive response code returned else remove this override part
return super.parseNetworkResponse(response);
}
};
//and then you pass json data to volley
VolleySingleton.getInstance(getActivity()).addToRequestQueue(jsonObjReq);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With