Latest Tweets

 

Loading unscaled bitmaps compatibly in Android 1.5 and 1.6

I’ve just started retargeting my applications for the latest version of Android (1.6) which introduces full support for different screen densities. The responsibility for scaling bitmap resources to match the screen density falls to the BitmapFactory class.

This is a new behaviour applied to existing methods; I haven’t got enough experience with the new SDK to form an opinion, but it looks as though the new functionality will do exactly what you want it to in most situations; it should simply be a case of moving resources to an appropriate ‘density directory’ (see the resources i18n guide for details).

But there are some instances where you don’t want your images scaled to match the screen density. One case is with images that you will scale within your application, usually when drawing them to a canvas. This occurs in my Daisy Garden application – different garden designs are created from a set of masked tiles which I don’t want pre-scaled.

In 1.6 there is support for density independent bitmaps - these can be placed in a “drawable-nodpi” resources folder. Unfortunately it seems that this isn’t properly supported for 1.5 (it appears that bitmaps loaded from this folder always come out as 1px squares). Alternatively, there is also flag: BitmapFactory.Options.inScaled which you can set to false to disable the scaling, but this is new in 1.6 so isn’t available in applications that aim for compatibility with 1.5.

So I think there’s no option but to produce a utility class that switches code path depending on the API number. It’s not a big deal (it took me longer to write this post) but it might save someone else some time. It’s not documented, but simple to use, just call:

UnscaledBitmapLoader.loadFromResource()

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Build;

public abstract class UnscaledBitmapLoader {

    public static final UnscaledBitmapLoader instance;

    static {
        instance = Integer.parseInt(Build.VERSION.SDK) < 4 ? new Old() : new New();
    }

    public static Bitmap loadFromResource(Resources resources, int resId, BitmapFactory.Options options) {
        return instance.load(resources, resId, options);
    }

    private static class Old extends UnscaledBitmapLoader {

        @Override
        Bitmap load(Resources resources, int resId, Options options) {
            return BitmapFactory.decodeResource(resources, resId, options);
        }

    }

    private static class New extends UnscaledBitmapLoader {

        @Override
        Bitmap load(Resources resources, int resId, Options options) {
            if (options == null) options = new BitmapFactory.Options();
            options.inScaled = false;
            return BitmapFactory.decodeResource(resources, resId, options);
        }

    }

    abstract Bitmap load(Resources resources, int resId, BitmapFactory.Options options);

}
blog comments powered by Disqus