Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android background image slows down app

I am using a viewpager to swipe amongst fragments in my app. I define the background in the XML, so

android:background="@drawable/bg_final"

If I use a simple background color, my app works very smooth. If I use it with this background image, fps decreases and my app becomes only passable. It is not slow, just not so smooth, however on weaker devices it could work laggy. Is it a bad way to apply a background image? The whole image is a 480x800 png with the size of 14.7kB. What might be the problem?

(the backgrounds of the fragments are transparent, the viewpager is in a main.xml which has its background with this image)

like image 465
Jani Bela Avatar asked Jan 10 '13 23:01

Jani Bela


4 Answers

The reason for this could be that the image is being stretched, and Android has performance issues with stretching background images.

Instead, you should either replace the background image with either a background color or see this answer to have the image repeat instead of stretch.

like image 108
Oleg Vaskevich Avatar answered Oct 10 '22 03:10

Oleg Vaskevich


There are lots of answers out there that point to pre-scaling your bitmap. This is very imporant and you should do it if you can, however after trying several different things, the biggest performance gain I experienced was to create a view and override the onDraw method.

The class could be as simple as this:

public class DTImageView extends View {

     public Bitmap imageBitmap;

     public DTImageView(Context context) { 
         super(context); 
     } 

     @Override
     protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if(imageBitmap != null)
          canvas.drawBitmap(imageBitmap, 0, 0, null); 
     }
}

Invoke the code using a prescaled bitmap:

 DTImageView bgImageView = new DTImageView(context);
 bgImageView.imageBitmap = Bitmap.createScaledBitmap(bitmap,width,height,true);

At this point you can add this view to the view hierarchy where it belongs. In my case, my view hierarchy had a bgImage, a middle ground where all the other functionality happened, and fgImage.

Use the android sdk tool Hierarchy Viewer to profile the app and see how fast each view is taking to draw. My app spent 30-40ms drawing the bgImage and fgImage. Pre-scaling and overriding onDraw reduced that 30-40ms to about 1.5ms.

Here is a screenshot of the Draw performance for one of my views before and after:

BEFORE: Using setImageBitmap instead of overriding onDraw.

AFTER: Using the above DTImageView which simply overrides OnDraw

like image 29
Christopher Rathgeb Avatar answered Nov 08 '22 05:11

Christopher Rathgeb


I'm a bit late, but this just bit me, and when running the GPU debugger, I noticed that the system scaled up my image! I had a 1920x1080 image, and it showed up as a 3780x6720 texture!

Ideally, you should have textures for each density in the respective folder (res/drawable-mdpi, res/drawable-hdpi, etc).

However, if you think your one texture is fine, put it into res/drawable-nodpi, not res/drawable. If you put it into res/drawable-nodpi, the system won't scale it up based on the dpi.

In my case, it changed a simple UI from 10fps on a Pixel XL to the full frame rate of 60fps.

like image 8
EboMike Avatar answered Nov 08 '22 05:11

EboMike


I had a background image, not big in size, but with weird dimensions - therefore the stretching and bad performance. I made a method with parameters Context, a View and a drawable ID(int) that will match the device screen size. Use this in e.g a Fragments onCreateView to set the background.

public void setBackground(Context context, View view, int drawableId){
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), drawableId);
    int width = Resources.getSystem().getDisplayMetrics().widthPixels;
    int height = Resources.getSystem().getDisplayMetrics().heightPixels;
    bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
    BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), bitmap);
    view.setBackground(bitmapDrawable);
}
like image 3
ZooMagic Avatar answered Nov 08 '22 04:11

ZooMagic