我在应用程序中使用Volley库。
在onresponse监听器中我需要InputStream作为响应
我怎么得到它?
答案 0 :(得分:6)
BasicNetwork
的大量代码,然后更改处理请求的一些行为,如果传递特殊请求则使其不同,使用MyNetworkResponse
包装该响应最终在自定义NeededInsRequest
中获取InputStream。
import android.os.SystemClock;
import com.android.volley.*;
import com.android.volley.toolbox.BasicNetwork;
import com.android.volley.toolbox.ByteArrayPool;
import com.android.volley.toolbox.HttpStack;
import com.android.volley.toolbox.PoolingByteArrayOutputStream;
import org.apache.http.*;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.cookie.DateUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class MyNetwork extends BasicNetwork {
private static int SLOW_REQUEST_THRESHOLD_MS = 3000;
private static int DEFAULT_POOL_SIZE = 4096;
/**
* @param httpStack HTTP stack to be used
*/
public MyNetwork(HttpStack httpStack) {
// If a pool isn't passed in, then build a small default pool that will give us a lot of
// benefit and not use too much memory.
this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
}
/**
* @param httpStack HTTP stack to be used
* @param pool a buffer pool that improves GC performance in copy operations
*/
public MyNetwork(HttpStack httpStack, ByteArrayPool pool) {
super(httpStack, pool);
}
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
InputStream responseIns = null;
Map<String, String> responseHeaders = new HashMap<String, String>();
try {
// Gather headers.
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry());
httpResponse = mHttpStack.performRequest(request, headers);
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// Handle cache validation.
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
request.getCacheEntry() == null ? null : request.getCacheEntry().data,
responseHeaders, true);
}
// Some responses such as 204s do not have content. We must check.
if (httpResponse.getEntity() != null) {
// Note : only particular request needed InputStream.
if (request instanceof NeededInsRequest) {
responseIns = httpResponse.getEntity().getContent();
} else {
responseContents = entityToBytes(httpResponse.getEntity());
}
} else {
// Add 0 byte response as a way of honestly representing a
// no-content request.
responseContents = new byte[0];
}
// if the request is slow, log it.
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusLine);
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
return new MyNetworkResponse(statusCode,
responseContents, responseIns, responseHeaders, false);
} catch (SocketTimeoutException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException e) {
attemptRetryOnException("connection", request, new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
int statusCode;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
if (responseContents != null || responseIns != null) {
networkResponse = new MyNetworkResponse(statusCode,
responseContents, responseIns, responseHeaders, false);
if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
statusCode == HttpStatus.SC_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else {
// TODO: Only throw ServerError for 5xx status codes.
throw new ServerError(networkResponse);
}
} else {
throw new NetworkError(networkResponse);
}
}
}
}
/**
* Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete.
*/
private void logSlowRequests(
long requestLifetime, Request<?> request, byte[] responseContents, StatusLine statusLine) {
if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) {
VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " +
"[rc=%d], [retryCount=%s]", request, requestLifetime,
responseContents != null ? responseContents.length : "null",
statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount());
}
}
/**
* Attempts to prepare the request for a retry. If there are no more attempts remaining in the
* request's retry policy, a timeout exception is thrown.
* @param request The request to use.
*/
private static void attemptRetryOnException(
String logPrefix, Request<?> request, VolleyError exception) throws VolleyError {
RetryPolicy retryPolicy = request.getRetryPolicy();
int oldTimeout = request.getTimeoutMs();
try {
retryPolicy.retry(exception);
} catch (VolleyError e) {
request.addMarker(
String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));
throw e;
}
request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));
}
private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {
// If there's no cache entry, we're done.
if (entry == null) {
return;
}
if (entry.etag != null) {
headers.put("If-None-Match", entry.etag);
}
if (entry.serverDate > 0) {
Date refTime = new Date(entry.serverDate);
headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
}
}
protected void logError(String what, String url, long start) {
long now = SystemClock.elapsedRealtime();
VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url);
}
/** Reads the contents of HttpEntity into a byte[]. */
private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
PoolingByteArrayOutputStream bytes =
new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
byte[] buffer = null;
try {
InputStream in = entity.getContent();
if (in == null) {
throw new ServerError();
}
buffer = mPool.getBuf(1024);
int count;
while ((count = in.read(buffer)) != -1) {
bytes.write(buffer, 0, count);
}
return bytes.toByteArray();
} finally {
try {
// Close the InputStream and release the resources by "consuming the content".
entity.consumeContent();
} catch (IOException e) {
// This can happen if there was an exception above that left the entity in
// an invalid state.
VolleyLog.v("Error occured when calling consumingContent");
}
mPool.returnBuf(buffer);
bytes.close();
}
}
/**
* Converts Headers[] to Map<String, String>.
*/
private static Map<String, String> convertHeaders(Header[] headers) {
Map<String, String> result = new HashMap<String, String>();
for (Header header : headers) {
result.put(header.getName(), header.getValue());
}
return result;
}
}
将BasicNetwork替换为初始化它的MyNetwork
。
import com.android.volley.NetworkResponse;
import java.io.InputStream;
import java.util.Map;
public class MyNetworkResponse extends NetworkResponse {
public MyNetworkResponse(int statusCode, byte[] data, InputStream ins,
Map<String, String> headers, boolean notModified) {
super(statusCode, data, headers, notModified);
this.ins = ins;
}
public MyNetworkResponse(byte[] data, InputStream ins) {
super(data);
this.ins = ins;
}
public MyNetworkResponse(byte[] data, InputStream ins, Map<String, String> headers) {
super(data, headers);
this.ins = ins;
}
public final InputStream ins;
}
扩展NetworkResponse
,添加一个InputStream字段。
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import java.io.InputStream;
public class NeededInsRequest extends Request<byte[]> {
private final Response.Listener<byte[]> mListener;
public NeededInsRequest(int method, String url, Response.Listener<byte[]> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
// this request would never use cache.
setShouldCache(false);
mListener = listener;
}
@Override
protected void deliverResponse(byte[] response) {
mListener.onResponse(response);
}
@Override
protected Response<byte[]> parseNetworkResponse(NetworkResponse response) {
if (response instanceof MyNetworkResponse) {
// take the InputStream here.
InputStream ins = ((MyNetworkResponse) response).ins;
}
return Response.success(response.data, HttpHeaderParser.parseCacheHeaders(response));
}
}
执行NeededInsRequest
以获取InputStream,然后执行任何操作。
我没有测试这些代码,但我认为它可以提供帮助,如果有一些错误,我很乐意知道它。
答案 1 :(得分:1)
我向VinceStyling's answer发了评论,向GitHub提供了他的代码更改和示例,所以这里是: https://github.com/georgiecasey/android-volley-inputstream-as-response
您需要的Volley编辑的相关提交在这里: https://github.com/georgiecasey/android-volley-inputstream-as-response/commit/62d9b9132c4f66b2268e9099d418b28884c26ce5
我需要在Volley中使用InputStream从一个URL下载图像,将响应作为InputStream获取并执行分段上传到另一个URL。从那时起,我不得不使用竞争的loopj Android HTTP库,并发现我的用例在该库中更容易。所以我切换到这个应用程序的库。如果有人想要那个代码,请留下另一条评论。