Skip to content
This repository has been archived by the owner on Oct 15, 2018. It is now read-only.

put(Bitmap) is really slow #26

Closed
pboos opened this issue Apr 29, 2013 · 10 comments
Closed

put(Bitmap) is really slow #26

pboos opened this issue Apr 29, 2013 · 10 comments

Comments

@pboos
Copy link

pboos commented Apr 29, 2013

I noticed that put seems to be pretty slow. So I did some tests:

53ms Connecting
525ms Downloading image
39ms Resizing image
191ms Saving resized image to sd card (manually)
969ms Put into cache (Android-BitmapCache)

So currently I am wondering WHAT is taking so long in the put method? It can't be saving the image to the SD card, since that only takes less than 1/4 of that time.

Any Ideas why that could be and how I could speed this up?

As well I looked at the speed when getting the image:
119ms Get image from cache (Android-BitmapCache)
80ms Decode bitmap from file manually

So I wonder what is taking those 40 additional milliseconds when getting the image.

Sorry for being so picky :). But this speed problem is currently the only reason why I am considering to writing my own cache. But I hope we can get this run faster :)

@chrisbanes
Copy link
Owner

Hi Patrick, can you post the code you use to create the cache?

@chrisbanes
Copy link
Owner

Also, can you post the code around the put_() and get_() calls?

@pboos
Copy link
Author

pboos commented Apr 30, 2013

Creating of cache:

File cacheLocation = new File(Environment.getExternalStorageDirectory()
                + "/Android/data/jp.co.cyberagent.httpsimple.sample.simple");
mBitmapCache = new BitmapLruCache.Builder(this)
                .setDiskCacheEnabled(true)
                .setDiskCacheLocation(cacheLocation)
                .setMemoryCacheEnabled(true)
                .setMemoryCacheMaxSizeUsingHeapSize(0.5f)
                .build();

Calling of get and put areas:

        private long mLastTimeStamp;
        private void logTime(String message) {
            if (mLastTimeStamp != 0) {
                Log.i("TEST", (System.currentTimeMillis() - mLastTimeStamp) + "ms " + message);
            }
            mLastTimeStamp = System.currentTimeMillis();
        }

        @Override
        public void run() {
            if (mCanceled) {
                return;
            }

            HttpSimple httpSimple = mContract.getHttpSimple();
            BitmapLruCache bitmapCache = mContract.getBitmapCache();

            logTime("Start");
            Drawable drawable = bitmapCache.get(mUrl);
            if (drawable != null) {
                show(drawable);
                logTime("Drawable from Cache");
                return;
            }

            try {
                // download
                mRequest = httpSimple.get(mUrl);
                InputStream inputStream = mRequest
                        .receiveProgress(this)
                        .inputStream();

                logTime("Connect to server");

                if (inputStream == null) {
                    return;
                }

                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                if (bitmap == null) {
                    return;
                }

                logTime("Download/decode bitmap");

                // resize
                Bitmap resizedBitmap =
                        Bitmap.createScaledBitmap(bitmap, mImageSize, mImageSize, false);

                logTime("Resize Bitmap");

                resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "test.png")));
                logTime("Compress as JPEG/100 to sd card (manually)");

                // cache
                // TODO this is slow
                drawable = bitmapCache.put(mUrl, resizedBitmap);
                logTime("Put into bitmapCache");

                // display
                show(drawable);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

But I think I found the problem. compressing to PNG takes a lot longer than compressing to JPEG. In the above times I was compressing to JPEG. When I switched to compress to PNG (as you do), than I get about the same times.

Same applies by getting. I guess PNG is just not fast enough for big pictures (mine are around 1000x1000).

So would it be possible to switch to JPEG (maybe through some setting)? For my use case, that would speed up things a lot.

Times with PNG:

I/TEST    (10482): 334ms Connect to server
I/TEST    (10482): 954ms Download/decode bitmap
I/TEST    (10482): 111ms Resize Bitmap
I/TEST    (10482): 2199ms Compress as PNG/100 to sd card (manually)
I/TEST    (10482): 1986ms Put into bitmapCache

JPEG

I/TEST    (12746): 114ms Connect to server
I/TEST    (12746): 311ms Download/decode bitmap
I/TEST    (12746): 278ms Resize Bitmap
I/TEST    (12746): 911ms Compress as JPEG/100 to sd card (manually)
I/TEST    (12746): 3082ms Put into bitmapCache

chrisbanes pushed a commit that referenced this issue Apr 30, 2013
…pression parameters.

Also tidy up the outputstream handling.
@chrisbanes
Copy link
Owner

The commit above allows you to specify the compression format.

FYI, you can completely omit the encode and decode though by using the put(String, InputStream) or put(String, InputStream, BitmapFactory.Options) methods.

@pboos
Copy link
Author

pboos commented Apr 30, 2013

Thank you very much!

Yes, using the InputStream would be the best method to use. But images I am getting are not the correct size (sadly can not use a resizing image API service).

@chrisbanes
Copy link
Owner

You could use inSampleSize with the InputStream method ;)

@pboos
Copy link
Author

pboos commented Apr 30, 2013

I could, but it does not do the job :). Problem of inSampleSize are 2:

  1. It only allows me to reduce the size by factor 2. But to make android render nicely I need the exact size. ImageView scaling runs on UI thread which makes ListView/ViewPager pretty slow...
  2. To know the inSampleSize I need to use I need to run it once with inJustDecodeBounds. With a stream from the internet, that would be bad. Okay, I could quickly store it as a file and do it with a FileInputStream that i then as well give to BitmapCache.

For those reasons, the method you created seems to be the best for the task. Or do you have another idea?
Thx a lot for a great library!

@chrisbanes
Copy link
Owner

Ah ok. I just want to make sure you were aware of this more efficient way.

Just to correct you a little bit, ImageView scaling works via draw matrices, which is actually efficient (especially on GPU accelerated canvases).

@pboos
Copy link
Author

pboos commented May 1, 2013

Thank you for the correction! Will have to try that out again. Last time I tried I think ListView had small stutters because of image scaling. Or maybe it was something else.

@nikclayton
Copy link

On 1 May 2013 12:27, Patrick Boos notifications@github.com wrote:

Thank you for the correction! Will have to try that out again. Last time I
tried I think ListView had small stutters because of image scaling. Or
maybe it was something else.

Might be related to
https://plus.google.com/113058165720861374515/posts/iTk4PjgeAWX

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants