我刚开始从我现有的网络库移植到Android的Volley。到目前为止,我已经成功实施了Volleys ImageLoader。现在,我正在尝试启动并运行我的第一个http调用,但是我发现了这个错误。
注意:我故意以PATCH请求开始,因为我会经常使用它们。另外,我的Volley DOES版本支持补丁: 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
堆栈跟踪:
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请求
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);
是的,我计划最终为StringRequest,JsonObjectRequest等构建类......但是目前我只想让它运行起来。
另外,如果您对addCookie感到疑惑,我现在更喜欢将我的cookie保存在首选项中,因为我对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);
}
}
}
答案 0 :(得分:3)
问题:
Volleys HurlStack(HttpUrlConnection)确实有PATCH的支持代码。但是,每当您尝试发出PATCH请求时,它似乎仍会抛出我的标题和堆栈跟踪中发布的异常。
黑客解决方案:
1)强制Volley使用HttpClientStack。
以下是我的VolleySingleton构造函数的更新版本。这“有效”,但显然浪费了Hurl实现,如果(Build.VERSION.SDK_INT&gt; = 9)则认为更好。不用说谷歌计划将来完全从apache HttpClient转移。
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)继续使用上面的VolleySingleton进行补丁;将其重命名为VolleySingletonPatch(),然后为所有其他NON-PATCH调用创建一个Default VolleySingleton()。 (优于1,但仍然不是最优的)
3)尽管Volley已经实现了PATCH,但解决了HurlStack中抛出的异常。这将是最好的,但我更愿意避免直接修补Volley或不必要地扩展我自己的HttpStack。
我要留下这个没有答案的,因为我非常感谢任何洞察力,当然还有比我在这里提出的更好的选择。
答案 1 :(得分:2)
我也有这个问题,我的解决方案就是放弃底层的内置Apache HTTP组件,并使用来自Square的OkHttp库,使用this HttpStack
implementation作为Volley,使用OkHttp作为其传输。效果很好。
答案 2 :(得分:0)
我知道这个问题很旧,但是提供解决方案可以帮助尚未遇到相同挑战的人
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);