So a part of my app downloads a large number (~1600) of images to SdCard using an IntentService. I previously used Glide, but now want to switch to OkHttp, since it seems to be faster and less battery consuming. This is my current code:
for (int i = 1; i < 1600; i++) {
try {
Request request = new Request.Builder()
.url(imageUrls[i])
.build();
Response response = client.newCall(request).execute();
File testDirectory = new File(Environment.getExternalStorageDirectory()
+ "/downloadTest");
if (!testDirectory.exists())
testDirectory.mkdirs();
OutputStream outputStream = new FileOutputStream(new File(testDirectory,
"testImage" + i + ".png"));
InputStream inputStream = response.body().byteStream();
byte[] buffer = new byte[1024];
int read;
while ((read = inputStream.read(buffer, 0, buffer.length)) >= 0)
outputStream.write(buffer, 0, read);
outputStream.flush();
outputStream.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Is there any way I could optimize this code to make downloading faster?
You can use Okio instead of InputStream/OutputStream to save some copies. Something like this:
BufferedSink sink = Okio.buffer(Okio.sink(new File(testDirectory, "testImage" + i + ".png")));
sink.writeAll(response.body().source());
sink.close();
response.body().close();
See this post for an explanation of why this is faster.
the easiest way is:
InputStream inputStream = response.body().byteStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
and save the bitmap as jpg:
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
Related
I need to save the .svg in the Internal storage of android application and retrieve it and set it to the ImageView.
I am not able to save the .svg file. i am using this method -
File cacheDir = ctx.getCacheDir();
f = new File(cacheDir, name + ".png");
try {
InputStream in = new java.net.URL(imageurl).openStream();
mIcon = BitmapFactory.decodeStream(in);
try {
FileOutputStream out = new FileOutputStream(
f);
mIcon.compress(
Bitmap.CompressFormat.JPEG,
100, out);
out.flush();
out.close();
return f;
} catch (FileNotFoundException e) {
return null;
} catch (IOException e) {
return null;
}
} catch (Exception e) {
return null;
}
Why are you decoding SVG into bitmap ? I'm not sure it is possible.
But if you want to save the SVG file to storage, just copy you input stream to the output stream.
Simple java solution :
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
or with IOUtils
If you want to display your SVG file, look at https://github.com/pents90/svg-android/tree/master/svgandroid
I am facing this issue in uploading the file to the google drive, i am uploading the recorded audio to the google drive at that time this exception is occurring
The code used for writing the content in the file
OutputStream outputStream = result.getDriveContents().getOutputStream();
FileInputStream fis;
try {
fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n;
while (-1 != (n = fis.read(buf)))
baos.write(buf, 0, n);
byte[] photoBytes = baos.toByteArray();
outputStream.write(photoBytes);
outputStream.close();
outputStream = null;
fis.close();
fis = null;
Log.e("File Size", "Size " + file.length());
} catch (FileNotFoundException e) {
Log.v("EXCEPTION", "FileNotFoundException: " + e.getMessage());
} catch (IOException e1) {
Log.v("EXCEPTION", "Unable to write file contents." + e1.getMessage());
}
The exception occurs in the line ` baos.write(buf, 0, n);
Please help me how to solve this error.`
Writing to a ByteArrayOutputStream first means that the complete file will end up in the JVM's heap. Depending on the file size and heap size this might not be possible, hence the exception. If you don't need the ByteArrayOutputStream for anything else just write directly to outputStream:
OutputStream outputStream = result.getDriveContents().getOutputStream();
FileInputStream fis;
try {
fis = new FileInputStream(file);
byte[] buf = new byte[1024];
int n;
while (-1 != (n = fis.read(buf)))
outputStream.write(buf, 0, n);
} catch (FileNotFoundException e) {
Log.v("EXCEPTION", "FileNotFoundException: " + e.getMessage());
} catch (IOException e1) {
Log.v("EXCEPTION", "Unable to write file contents." + e1.getMessage());
} finally {
outputStream.close();
fis.close();
Log.e("File Size", "Size " + file.length());
}
P.S.: nulling the references should not be necessary if they go out of scope soon...
You are getting OOM because you try to read full file into the memory before writing it to the google drive outputStream. The file may be too large to be stored in the memory. This way you need to write it part by part. It is easy to accomplish using this method:
private static final int BUFFER_SIZE = 1024;
public static long copy(InputStream from, OutputStream to)
throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
long total = 0;
while (true) {
int r = from.read(buffer);
if (r == -1) {
break;
}
to.write(buffer, 0, r);
total += r;
}
return total;
}
The method will return number of bytes copied.
I'm hitting an URL and saving the returned image response in cache dir. If I try to save Bitmap from Returned response inputstream then I get correct Bitmap. Now after saving that response inputstream in cache and after fetching it I'm getting null Bitmap
Write inputStream to cache dir -
String root = mContext.getCacheDir().toString();
String path = root + "/tomorrow.jpg";
try {
final File file = new File(path);
final OutputStream output = new FileOutputStream(file);
try {
try {
final byte[] buffer = new byte[1024];
int ch;
while ((ch = in.read(buffer)) != -1)
output.write(buffer, 0, ch);
} finally {
output.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}catch(Exception e){
e.printStackTrace();
}
now I'm reading the file from cache dir -
FileInputStream fin = null;
try {
fin = new FileInputStream(new File(path));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bmp1 = BitmapFactory.decodeStream(fin);
I'd like to thanks Dimitri Budiansky for guiding me. Fix as below-
//final byte[] buffer = new byte[1024];
//int ch;
//while ((ch = in.read(buffer)) != -1)
//output.write(buffer, 0, ch);
I commented above lines. Simply add below line.
bmp.compress(Bitmap.CompressFormat.PNG, 100, output);
for clarification u may check this Link
i am writing the PDF's to sdcard and using the below code :
byte[] data = new byte[20000];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
InputStream fileInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
while ((nRead = fileInputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] bytesToWrite = buffer.toByteArray();
fileInputStream.read(bytesToWrite);
fileInputStream.close();
FileOutputStream fileOutputStream = null;
String outputFileName = outputDirName + "/" + fileName;
fileOutputStream = new FileOutputStream(outputFileName);
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
bos.write(bytesToWrite);
bos.flush();
bos.close();
It works fine if i am trying to write 20 PDFs in one shot, but if its more than that it gives me OutOfMemory error.
what might be the issue ?
You are storing the entire file into RAM with your ByteArrayOutputStream, then copying it from RAM onto disk. This is likely what's causing your OutOfMemoryError.
It would be much more efficient to read a chunk into RAM, and then flush to disk immediately repeatedly. I've rewritten your code to do this.
byte[] data = new byte[20000];
FileOutputStream fileOutputStream = null;
String outputFileName = outputDirName + "/" + fileName;
fileOutputStream = new FileOutputStream(outputFileName);
int nRead;
InputStream fileInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
while ((nRead = fileInputStream.read(data, 0, data.length)) != -1) {
fileOutputStream.write(data,0,nRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
I am loading a image from the web to the local android phone. The code that I have for writing to a file is as follows
BufferedInputStream bisMBImage=null;
InputStream isImage = null;
URL urlImage = null;
URLConnection urlImageCon = null;
try
{
urlImage = new URL(imageURL); //you can write here any link
urlImageCon = urlImage.openConnection();
isImage = urlImageCon.getInputStream();
bisMBImage = new BufferedInputStream(isImage);
int dotPos = imageURL.lastIndexOf(".");
if (dotPos > 0 )
{
imageExt = imageURL.substring(dotPos,imageURL.length());
}
imageFileName = PATH + "t1" + imageExt;
File file = new File(imageFileName);
if (file.exists())
{
file.delete();
Log.d("FD",imageFileName + " deleted");
}
ByteArrayBuffer baf = new ByteArrayBuffer(255);
Log.d("IMAGEWRITE", "Start to write image to Disk");
int current = 0;
try
{
while ((current = bisMBImage.read()) != -1)
{
baf.append((byte) current);
}
FileOutputStream fos = new FileOutputStream(file);
fos.write(baf.toByteArray());
fos.close();
Log.d("IMAGEWRITE", "Image write to Disk done");
}
catch (IOException e)
{
e.printStackTrace();
}
isImage.close();
}
catch (IOException e)
{
Log.d("DownloadImage", "Error: " + e);
}
finally
{
isImage = null;
urlImageCon = null;
urlImage = null;
}
For some reason the whole writing to a file takes 1 minute. Is there a way I can optimize this ?
Your buffer is very small: 255 bytes. You could make it 1024 times bigger (255 kilobytes). This is an acceptable size and this would certainly speed up the thing.
Also, this is very slow as it reads the bytes one by one:
while ((current = bisMBImage.read()) != -1) {
baf.append((byte) current);
}
You should try using the array version of read() instead: read(byte[] buffer, int offset, int byteCount) with an array as large as what I have described above.
You should use the Android HttpClient for file fetching over the java URL Connection. Also your Buffer is very small.
Try this snipped:
FileOutputStream f = new FileOutputStream(new File(root,"yourfile.dat"));
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
InputStream is = response.getEntity().getContent();
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = is.read(buffer)) > 0 ) {
f.write(buffer,0, len1);
}
f.close();