box-android-sdk
box-android-sdk copied to clipboard
How to get inpustream when downloading a file?
With other cloud vendors I am able with their APIs to get an InputStream when I make a request to download a file. How do I do with this SDK? I do not understand why you do not want to implement this method: https://github.com/box/box-android-sdk/issues/53 My application supports multiple clouds. I can upload to Box from dropbox, googledrive or onedrive because sdks provide me an InputStream ... but I can not do the reverse ... except going through a pipedInputStream ... it's annoying!
Thanks a lot.
The sdk is designed to simplify the work flow required for most developer applications so we need control of the original input stream to handle error cases and progress reporting. Your use case is a bit advanced especially in the sense that it can error out from the other api's reading logic.
I'd recommend copying the code for DownloadRequestHandler into a custom class and adding your custom logic such that instead of calling SdkUtils.copyStream you call whatever api you needed the InputStream for.
Hi @doncung , thanks for support. I 'd add this class in DownloadRequestHandler:
protected static final int DEFAULT_NUM_RETRIES = 2;
protected static final int DEFAULT_MAX_WAIT_MILLIS = 90 * 1000;
protected int mNumAcceptedRetries = 2;
protected int mRetryAfterMillis = 1000;
/**
* Constructs a DownloadRequestHandler with the default parameters.
*
* @param request a BoxRequestDownload this handler is responsible for.
*/
public DownloadRequestHandlerToInput(BoxRequestDownload request) {
super(request);
}
protected InputStream getInputStream(BoxDownload downloadInfo) {
return mRequest.mInputStream;
}
@Override
public BoxDownload onResponse(Class clazz, BoxHttpResponse response) throws IllegalAccessException, InstantiationException, BoxException {
String contentType = response.getContentType();
long contentLength = -1;
if (response.getResponseCode() == BoxConstants.HTTP_STATUS_TOO_MANY_REQUESTS) {
return retryRateLimited(response);
} else if (response.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED) {
try {
// First attempt to use Retry-After header, all failures will eventually fall back to exponential backoff
if (mNumAcceptedRetries < DEFAULT_NUM_RETRIES) {
mNumAcceptedRetries++;
mRetryAfterMillis = getRetryAfterFromResponse(response, 1);
} else if (mRetryAfterMillis < DEFAULT_MAX_WAIT_MILLIS) {
// Exponential back off with some randomness to avoid traffic spikes to server
mRetryAfterMillis *= (1.5 + Math.random());
} else {
// Give up after the maximum retry time is exceeded.
throw new BoxException.MaxAttemptsExceeded("Max wait time exceeded.", mNumAcceptedRetries);
}
Thread.sleep(mRetryAfterMillis);
return (BoxDownload) mRequest.send();
} catch (InterruptedException e) {
throw new BoxException(e.getMessage(), response);
}
} else if (response.getResponseCode() == HttpURLConnection.HTTP_OK || response.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
// mInputStream = response.getHttpURLConnection().getInputStream();
String contentLengthString = response.getHttpURLConnection().getHeaderField("Content-Length");
String contentDisposition = response.getHttpURLConnection().getHeaderField("Content-Disposition");
try {
// do this manually since the older 1.6 convenience method returns int.
contentLength = Long.parseLong(contentLengthString);
} catch (Exception e) {
// ignore any errors here.
}
String contentRange = response.getHttpURLConnection().getHeaderField("Content-Range");
String date = response.getHttpURLConnection().getHeaderField("Date");
String expirationDate = response.getHttpURLConnection().getHeaderField("Expiration");
BoxDownload downloadInfo = new BoxDownload(contentDisposition, contentLength, contentType, contentRange, date, expirationDate) {
@Override
public File getOutputFile() {
if (mRequest.getTarget() == null) {
return null;
}
if (mRequest.getTarget().isFile()) {
return mRequest.getTarget();
}
if (!SdkUtils.isEmptyString(getFileName())) {
return new File(mRequest.getTarget(), getFileName());
}
return super.getOutputFile();
}
};
if (mRequest.mDownloadStartListener != null) {
mRequest.mDownloadStartListener.onStart(downloadInfo);
}
InputStream input = null;
try {
mInputStream = response.getHttpURLConnection().getInputStream();
//mInputStream = response.getBody();
Log.i("INPUT1","ok!!!");
} catch (Exception e) {
throw new BoxException(e.getMessage(), e);
} finally {
if (mRequest.getTargetStream() == null) {
// if this is not from a stream, meaning we created the stream we will close the outputStream as well.
}
}
return downloadInfo;
}
return new BoxDownload(null, 0, null, null, null, null);
}
}
and to get the inpustream :
else if (fromProvider.equals("Box")){
BoxRequestDownload request = cloudItem.getBoxApiFile().getDownloadRequest(fileIdOrPath);
try {
request.send();
input = request.getInputStream();
} catch (BoxException e) {
e.printStackTrace();
}
]
I obtain a inputStream but the socket is closed.
Any idea?
Always use the getBody method as the actual input stream varies. Also the sdk is designed such that send acts sychronously completing its job and cleans up. As such you will need some kind of listener object that will give you the input stream when it is ready where you can do your logic to fully read it out. Then after calling send that listener should get triggered and you will need to read out the input stream.
On Jul 22, 2017 6:25 AM, "Aristide13" [email protected] wrote:
Hi @doncung https://github.com/doncung , thanks for support. I 'd add this class in DownloadRequestHandler: ` public static class DownloadRequestHandlerToInput extends BoxRequestHandler {
protected static final int DEFAULT_NUM_RETRIES = 2; protected static final int DEFAULT_MAX_WAIT_MILLIS = 90 * 1000; protected int mNumAcceptedRetries = 2; protected int mRetryAfterMillis = 1000; /** * Constructs a DownloadRequestHandler with the default parameters. * * @param request a BoxRequestDownload this handler is responsible for. */ public DownloadRequestHandlerToInput(BoxRequestDownload request) { super(request); } protected InputStream getInputStream(BoxDownload downloadInfo) { return mRequest.mInputStream; } @Override public BoxDownload onResponse(Class clazz, BoxHttpResponse response) throws IllegalAccessException, InstantiationException, BoxException { String contentType = response.getContentType(); long contentLength = -1; if (response.getResponseCode() == BoxConstants.HTTP_STATUS_TOO_MANY_REQUESTS) { return retryRateLimited(response); } else if (response.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED) { try { // First attempt to use Retry-After header, all failures will eventually fall back to exponential backoff if (mNumAcceptedRetries < DEFAULT_NUM_RETRIES) { mNumAcceptedRetries++; mRetryAfterMillis = getRetryAfterFromResponse(response, 1); } else if (mRetryAfterMillis < DEFAULT_MAX_WAIT_MILLIS) { // Exponential back off with some randomness to avoid traffic spikes to server mRetryAfterMillis *= (1.5 + Math.random()); } else { // Give up after the maximum retry time is exceeded. throw new BoxException.MaxAttemptsExceeded("Max wait time exceeded.", mNumAcceptedRetries); } Thread.sleep(mRetryAfterMillis); return (BoxDownload) mRequest.send(); } catch (InterruptedException e) { throw new BoxException(e.getMessage(), response); } } else if (response.getResponseCode() == HttpURLConnection.HTTP_OK || response.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) { // mInputStream = response.getHttpURLConnection().getInputStream(); String contentLengthString = response.getHttpURLConnection().getHeaderField("Content-Length"); String contentDisposition = response.getHttpURLConnection().getHeaderField("Content-Disposition"); try { // do this manually since the older 1.6 convenience method returns int. contentLength = Long.parseLong(contentLengthString); } catch (Exception e) { // ignore any errors here. } String contentRange = response.getHttpURLConnection().getHeaderField("Content-Range"); String date = response.getHttpURLConnection().getHeaderField("Date"); String expirationDate = response.getHttpURLConnection().getHeaderField("Expiration"); BoxDownload downloadInfo = new BoxDownload(contentDisposition, contentLength, contentType, contentRange, date, expirationDate) { @Override public File getOutputFile() { if (mRequest.getTarget() == null) { return null; } if (mRequest.getTarget().isFile()) { return mRequest.getTarget(); } if (!SdkUtils.isEmptyString(getFileName())) { return new File(mRequest.getTarget(), getFileName()); } return super.getOutputFile(); } }; if (mRequest.mDownloadStartListener != null) { mRequest.mDownloadStartListener.onStart(downloadInfo); } InputStream input = null; try { mInputStream = response.getHttpURLConnection().getInputStream(); //mInputStream = response.getBody(); Log.i("INPUT1","ok!!!"); } catch (Exception e) { throw new BoxException(e.getMessage(), e); } finally { if (mRequest.getTargetStream() == null) { // if this is not from a stream, meaning we created the stream we will close the outputStream as well. } } return downloadInfo; } return new BoxDownload(null, 0, null, null, null, null); }
}`
and to get the inpustream : `else if (fromProvider.equals("Box")){
BoxRequestDownload request = cloudItem.getBoxApiFile().getDownloadRequest(fileIdOrPath); try { request.send(); input = request.getInputStream(); } catch (BoxException e) { e.printStackTrace(); }
]` I obtain a inputStream but the socket is closed.
Any idea?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/box/box-android-sdk/issues/292#issuecomment-317183612, or mute the thread https://github.com/notifications/unsubscribe-auth/AAmHYnKF0em5bHT5sbz40zsfHnaOhNVEks5sQfg9gaJpZM4OXGTH .
Finaly i do the trikck like this :
-DownloadRequestHandlerToInput:
if (mRequest.mDownloadStartListener != null) {
try {
mInputStream = response.getBody();
} catch (Exception e) {
throw new BoxException(e.getMessage(), e);
mRequest.mDownloadStartListener.onStart(downloadInfo);
}
-And to get the inputstream and start sychronously the upload:
request = cloudItem.getBoxApiFile().getDownloadRequest(fileIdOrPath).setDownloadStartListener(new DownloadStartListener() {
@Override
public void onStart(BoxDownload downloadInfo) {
input = request.getInputStream();
// start the upload from other provider here
}
});
try {
request.send();
} catch (BoxException e) {
e.printStackTrace();
}
It's seem to work fine for me.
Thanks again.
I cannot get this to work A method to get an input stream would be great I have tried copying the code from DownloadRequestHandler but there are some protected variables that inhibit the process could you please make a method to get an input stream...