ImageView / WeakReference

Memory Cache – Part 2

In the previous article we looked at the theory behind weak references. In this article we’ll look at one use-case where a simple memory cache may speed things up.

First let’s put together a basic project to do this. We’ll create a new 2.3.3 project called MemoryCache including an Activity named MemoryCacheActivity, and modify main.xml to contain two ImageView objects wrapped in a LinearLayout:

[xml]


[/xml]

Next we’ll put an image in to the assets folder of our project .You can download the Styling Android logo from here.

Next we’ll create a utility class named Utils which will contain a single static method:

[java] final class Utils
{
private static final String TAG = MemCacheActivity.TAG;

public static Bitmap loadAsset( Context context,
String assetName )
{
Bitmap bitmap = null;
InputStream is = null;
try
{
is = context.getAssets().open( assetName );
bitmap = BitmapFactory.decodeStream( is );
} catch (Exception e)
{
Log.e( TAG, “Load Error”, e );
} finally
{
if (is != null)
{
try
{
is.close();
} catch (Exception e)
{
}
}
}
return bitmap;
}
}
[/java]

We’ll use this method a number of times, so we define it here as a static to make life easier later on.

You may be wondering why we are loading the image from assets and not simply including it as a drawable and loading it through the Resources. The reason for this is that Android itself employs some caching as part of the resources infrastructure, so you are already getting the benefit of memory caching. This will not be used when you obtain images from other sources, so we are loading from assets to simulate an alternate source.

Now we’ll change our MemoryCacheActivity:

[java] public class MemCacheActivity extends Activity {
public static final String TAG = “MemoryCache”;
public static final String ASSET_NAME = “sa.png”;

private ImageView imageView1 = null;
private ImageView imageView2 = null;
private MemoryCache memCache = null;

@Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.main );

imageView1 = (ImageView) findViewById( R.id.imageView1 );
imageView2 = (ImageView) findViewById( R.id.imageView2 );

loadManual();
}

private void loadManual()
{
TimingLogger tl = new TimingLogger( TAG, “Standard image loading” );
imageView1.setImageBitmap( Utils.loadAsset( this, ASSET_NAME ) );
tl.addSplit( “first” );
imageView2.setImageBitmap( Utils.loadAsset( this, ASSET_NAME ) );
tl.addSplit( “second” );
tl.dumpToLog();
}
[/java]

In our onCreate() we are setting the content view the main.xml which we defined earlier, getting references to the two ImageViews that we declared in our layout, creating an instance of our MemoryCache, and calling loadManual(). loadManual() will simply set the images on each of our ImageView objects by loading the bitmap twice using the utility method from MemoryCache.

If you haven’t encountered TimingLogger before, it is an extremely useful tool for performance monitoring in your app. You simply create a TimingLogger instance using a TAG similar to android.util.Log and a text description. You then call addSplit() with a text description repeatedly at various points within your code, and finally call dumpToLog() which will output all of the gathered information and split times to logcat. One thing that you must do is to set the log level to Verbose otherwise nothing will be output. This can be done in various ways as detailed here, but we’ll use:

[code] adb shell setprop log.tag.MemoryCache VERBOSE
[/code]

If we run this we see the following:

Memory Cahe
The working app

More importantly, we’ll get the following in our log:

[code] Standard image loading: begin
Standard image loading: 114 ms, first
Standard image loading: 92 ms, second
Standard image loading: end, 206 ms
[/code]

Out TimingLogger output shows us that both images are taking around 100ms to load, for a combined time of around 200ms. There will be some minor variations in image load times throughout our testing.

While this may seem rather trivial it could be come more of an issue if we are using large images which are going to take longer to load, or if we re-use the same image man times. In the next part of this series we’ll have a look at implementing a simple memory cache to make things a little more efficient.

The source code for this article can be found here.

© 2012, Mark Allison. All rights reserved.

Copyright © 2012 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

3 Comments

  1. Little typo just before call of loadManual()
    previous line: memCache = new MemoryCache( … … …
    shouldn’t be there in tutorial part 2.. It confused me but from source it’s clear that is forgoten.. 😉

    Otherwise perfect.. Big thank for this post.. Keep doing great job and enjoy Android wonderland.. 😉 Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.