I am using retrofit to download some media files like video,mp3, jpg, pdf,... in my application.threre is a problem when I want to download a large file with 55MB with the format of mp4. when I want to download this file I get an error like this:
OutOfMemoryError threw while trying to throw OutOfMemoryError; no stack trace available
this is my code:
private void downloadFile() {
ArrayList<FileModel> filesInDB = G.bootFileFromFileDB();
for (final FileModel fm : filesInDB) {
APIService downloadService = ServiceGenerator.createServiceFile(APIService.class, "username", "password");
//Id of apk file that you want to download
Call<ResponseBody> call = downloadService.downloadFileWithDynamicUrlSync("file/download/" + String.valueOf(fm.getFileId()));
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccess()) {
Log.d("LOGOO", "server contacted and has file");
boolean writtenToDisk = writeResponseBodyToDisk(response.body(), fm.getFileName(), fm.getFileExtension());
response = null;
Log.d("LOGOO", "file download was a success? " + writtenToDisk);
} else {
Log.d("LOGOO", "server contact failed");
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("LOGO", "Error is : " + t.getMessage());
Toast.makeText(ActivityInternet.this, R.string.internet_error, Toast.LENGTH_LONG).show();
Intent intent = new Intent(ActivityInternet.this, ActivityStartup.class);
startActivity(intent);
}
});
}
and this is 'writeResponseBodyToDisk' method that I'm using:
private boolean writeResponseBodyToDisk(ResponseBody body, String fileName, String fileExtension) {
try {
// Location to save downloaded file and filename
File futureStudioIconFile = new File(G.DIR_APP + fileName + fileExtension);
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(futureStudioIconFile);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
Log.d("LOGO", "file download: " + fileSizeDownloaded + " of " + fileSize);
}
outputStream.flush();
return true;
} catch (IOException e) {
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
return false;
}
}
finally this is my createServiceFile method:
public static <S> S createServiceFile(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
String credentials = username + ":" + password;
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", basic)
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,audio/mp4,image/jpeg,*/*;q=0.8")
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(serviceClass);
}
I really appreciate if you can help me :)
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space Usually, this error is thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.
The OutOfMemoryError Exception in Java looks like this: Usually, this error is thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.
Because the Java heap is insufficient to allocate this array, it throws a java.lang.OutOfMemoryError: Java heap space A java.lang.OutOfMemoryError: Java heap space can also occur in applications that use finalizers excessively.
As you can see, the first graph, the app is never able to really regain some of the memory used. It used up to about 300MB at one point before the OutOfMemoryError occurred. The second graph shows that the app is able to garbage collect, regain some memory and stays pretty consistent in its memory usage.
There are 4 things to notice when handling large file downloads in retrofit:
android:largeHeap="true"
in your AndroidManifest.xml
, as an attribute for the <application>
.@Streaming
annotation from Retrofit, in order to stream the solution and not read it as a whole, which encumbers memory.AsyncTask
as described in this link. In your case, this means calling writeResponseBodyToDisk
from within the AsyncTask
.Level.BODY
okhttp3
logging interceptor. Using it alongside a streamed response still keeps the entire response body in memory, negating the advantage of the @Streaming
support provided by retrofit.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