Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android download image from server and save to sdcard without using BitmapFactory

I am trying to create an application that use to download image from server and show it into listview. The problem that I made was the leak of memory and make my application crash. I was searching in Android blog such as this link, it show a great idea but it still not enough to do it with multiple thread. Some device of android can work with it but some device can only handle in the single thread and sometimes it cannot work at all.

My application has many activity and each of them has a Listview that need to display image quick as possible. Through the Google IO 2012 they use buffer to save the original image to SD Card and it solve the problem Leak memory but it make loading so slow since the image that need to download was too big.

My question is: Is there any way to scale image together with write image to SD Card? I figure out some possible solution is to use Skip byte in the inputstream object and I was able to find Width and Height also Bit per pixel of the image that I need to download.

The following code was use in Google IO 2012 and it work well with multiple threading, in my case I have 4 thread running in the background.

private void downloadAndWriteFile(final String url, final File file) throws OutOfMemoryError {
    BufferedOutputStream out = null;

    try {
        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setDoInput(true);
        conn.connect();

        final InputStream in = new BufferedInputStream(conn.getInputStream(), IO_BUFFER_SIZE_BYTES);    // buffer size 1KB
        out = new BufferedOutputStream(new FileOutputStream(file), IO_BUFFER_SIZE_BYTES);

        int b;
        while ((b = in.read()) != -1) {
            out.write(b);
        }
        out.close();
        conn.disconnect();
    }
    catch (Exception e) {
        Log.e(TAG, "!!downloadAndWriteFile " + e.getMessage());
        file.delete();
    }
}
like image 324
vsatkh Avatar asked Nov 13 '22 22:11

vsatkh


1 Answers

1) use the following code before setting your images to free the native object associated with this bitmap, and clear the reference to the pixel data. It simply allows it to be garbage collected if there are no other references.

BitmapDrawable drawable = (BitmapDrawable) myImage.getDrawable();
Bitmap bitmap = drawable.getBitmap();
if (bitmap != null)
{
    bitmap.recycle();
}

2) use this method to reduce the size of bitmap in memory:

/**
 * decodes image and scales it to reduce memory consumption
 * 
 * @param file
 * @param requiredSize
 * @return
 */
public static Bitmap decodeFile(File file, int requiredSize) {
    try {

        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(file), null, o);

        // The new size we want to scale to

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < requiredSize
                    || height_tmp / 2 < requiredSize)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;

        Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(file),
                null, o2);

        return bmp;

    } catch (FileNotFoundException e) {
    } finally {
        System.gc();
    }
    return null;
}
like image 200
Bobs Avatar answered Nov 15 '22 11:11

Bobs