androidbitmapimageviewimageurlimagehandler

Converting image url to bitmap quickly


I need to display the list of images from api in the list page. For that i used two approaches.

First Approach:
By converting the url to byte array and then converting it into bitmap.Please find the below code..

URL imageUrl = new URL(url);
URLConnection ucon = imageUrl.openConnection();

InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);

ByteArrayBuffer baf = new ByteArrayBuffer(500);
int current = 0;
while ((current = bis.read()) != -1) {
     /* This approach slowdown the process*/
     baf.append((byte) current);
}

byte[] img_ary= baf.toByteArray();

Converting byte array to bitmap:

ByteArrayInputStream imageStream = new ByteArrayInputStream(
                    imgUrl);
Bitmap theImage = BitmapFactory.decodeStream(imageStream);

Second Approach:
Image scaling based on height and width

private static final String TAG_iamge = "Image";
private static final int IO_BUFFER_SIZE = 4 * 1024;

public static Bitmap loadBitmap(String url) {
    Bitmap bitmap = null;
    InputStream in = null;
    BufferedOutputStream out = null;

    try {
        in = new BufferedInputStream(new URL(url).openStream(),
                IO_BUFFER_SIZE);

        final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
        out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
        copy(in, out);
        out.flush();

        final byte[] data = dataStream.toByteArray();
        BitmapFactory.Options options = new BitmapFactory.Options();

        options.inJustDecodeBounds = true;
        options.inDither = false;
        options.inPurgeable = true;
        options.inInputShareable = true;

        bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,
                options);

        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        int reqHeight = 500;
        int reqWidth = 500;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2
            // and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        int scale = inSampleSize;

        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        o2.inDither = false;
        o2.inPurgeable = true;
        o2.inInputShareable = true;
        return BitmapFactory.decodeByteArray(data, 0, data.length, o2);
    } catch (Exception e) {
        Log.e(TAG_iamge, "Could not load Bitmap from: " + url);
    } finally {
        closeStream(in);
        closeStream(out);
    }

    return bitmap;
}

private static void copy(InputStream in, OutputStream out)
        throws IOException {
    byte[] b = new byte[IO_BUFFER_SIZE];
    int read;
    while ((read = in.read(b)) != -1) {
        out.write(b, 0, read);
    }
}

private static void closeStream(Closeable stream) {
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException e) {
            android.util.Log.e("", "Could not close stream", e);
        }
    }
}

Both approaches making the APP very slow. So here is my questions..

  1. How can i quickly convert the url into bitmap without making the app slow?

  2. How the other apps(like flipcart) displaying the 1000>s of images, without any slow or hang?

    Please guide to get the answer.


Solution

  • There is a library named Picasso. which can efficiently load images from url. it can also load image from the File. all you wanted to do , write a line of code.

    example

    Picasso.with(context) //Context
        .load("http://i.imgur.com/DvpvklR.png") //URL/FILE
        .into(imageView)//an ImageView Object to show the loaded image; 
    

    It can also cache your image, so the loaded image could be able to load faster on the next time without wasting the data.

    There are many more options available in Picasso. Here is the documentation

    If you need rounded cornered bitmap

    Picasso.with(mContext)
        .load("your-image-url-or-file-or-drawable")
        .transform(new RoundedTransformation(200, 0))
        .fit()
        .into(imageView);
    

    RoundedTransformation.java

    import android.graphics.Bitmap;
    import android.graphics.Bitmap.Config;
    import android.graphics.BitmapShader;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.graphics.Shader;
    
    // enables hardware accelerated rounded corners
    // original idea here : http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
    public class RoundedTransformation implements com.squareup.picasso.Transformation {
        private final int radius;
        private final int margin;  // dp
    
        // radius is corner radii in dp
        // margin is the board in dp
        public RoundedTransformation(final int radius, final int margin) {
            this.radius = radius;
            this.margin = margin;
        }
    
        @Override
        public Bitmap transform(final Bitmap source) {
            final Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    
            Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
            canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);
    
            if (source != output) {
                source.recycle();
            }
    
            return output;
        }
    
        @Override
        public String key() {
            return "rounded";
        }
    }