Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6678721
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 26, 20262026-05-26T04:16:34+00:00 2026-05-26T04:16:34+00:00

Loooong time viewer, finally getting round to signing up here at StackOverflow! After a

  • 0

Loooong time viewer, finally getting round to signing up here at StackOverflow!

After a very long time searching for a way to do a scrolling background of a ViewGroup in Android, I’ve developed the following:

public class SlidingDrawable extends Drawable implements Drawable.Callback {
private static final String TAG = "SlidingDraw";
private static float STEP_SIZE = 1.0f;

private BitmapDrawable mBitmap;
private Context mContext;

private float mPosX;
private int mBitmapWidth;

private Runnable mInvalidater;
private Handler mHandler;

public SlidingDrawable(Context c){
    mContext = c;

    // use this as the callback as we're implementing the interface
    setCallback(this);

    mHandler = new Handler();
    mInvalidater = new Runnable(){
        @Override
        public void run(){
            // decrement the drawables step size
            mPosX -= SlidingDrawable.STEP_SIZE;

            /*
             * Check to see if the current position is at point where it should 
             * loop.  If so, reset back to 0 to restart
             */
            if(Math.abs(mPosX) >= mBitmapWidth) mPosX = 0;
            // redraw
            invalidateDrawable(null);
        }
    };
}
public static void setStepSize(float newSize){
    SlidingDrawable.STEP_SIZE = newSize;
}
public void createBitmap(String path, ViewGroup parent){
    // height of the parent container
    int height = parent.getHeight();

    /* Initialize local variables
     *  bgBitmap    - the resulting bitmap to send into SlidingDrawable instance
     *  imageStream - raw bitmap data to be decoded into bgBitmap
     */     
    WindowManager wMgr = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    int mScreenWidth = wMgr.getDefaultDisplay().getWidth();

    InputStream imageStream;
    Matrix imgMatrix = new Matrix();
    Bitmap bitmap = null;
    try {
        imageStream = mContext.getAssets().open(path);

        // create a temporary bitmap object for basic data
        Bitmap temp = BitmapFactory.decodeStream(imageStream);
        int width = temp.getWidth();

        // find the width difference as a percentage to apply to the 
        // transformation matrix
        float widthDifference = ((float)mScreenWidth) / (float)(width / 2);
        imgMatrix.postScale(widthDifference, 0, 0f, 0f);

        // create a copy of the bitmap, scaled correctly to maintain loop
        bitmap = Bitmap.createScaledBitmap(temp, (int)(width * widthDifference), height, true);

        // recycle the temp bitmap
        temp.recycle();
    } catch (IOException e) {
        e.printStackTrace();
    }   
    mBitmap = new BitmapDrawable(bitmap);

    // required
    mBitmapWidth = getIntrinsicWidth() / 2;
    Rect bounds = new Rect(0, 0, getIntrinsicWidth(), getIntrinsicHeight());        
    setBounds(bounds);
}
@Override
public void draw(Canvas canvas) {
    canvas.drawBitmap(mBitmap.getBitmap(), mPosX, 0f, null);
    scheduleDrawable(this, mInvalidater, SystemClock.uptimeMillis());
}
@Override
public int getOpacity() {
    return PixelFormat.OPAQUE;
}

@Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
    mHandler.postAtTime(what, who, when);
}

@Override
public void unscheduleDrawable(Drawable who, Runnable what) {
    mHandler.removeCallbacks(what, who);
}
@Override
public void invalidateDrawable(Drawable who) {
    invalidateSelf();
}
/* 
 * Methods not directly used or called omitted
 * 
 */

}

It is used in the Activity like so:

@Override
public void onWindowFocusChanged(boolean focus){
    // set the background of the root view of main.xml
    SlidingDrawable drawable = new SlidingDrawable(getApplicationContext());
    drawable.createBitmap("bgimg/basebg.jpg", mRoot);
    mRoot.setBackgroundDrawable(drawable);
}

Long story short, the basebg.jpg image is a tileable image roughly 1600×480. The constructor for SlidingDrawable scales and moves and yaddah yaddah. It works.

Now, the problem is, it seems really inefficient to do it like this. I can’t seem to find much information on this sort of implementation, so I’m in the dark on where I can cut CPU cycles, or even if I’m using the method calls correctly.

My questions include:

  • Is it better to drawBitmap as opposed to using setTranslate() or postTranslate and draw the bitmap using a Matrix?
  • Is it better to use drawBitmap, or the canvas functions such as translate(), save(), and restore()?
  • What rate does the draw() method get called at, and is there a way to limit it to, say, 24 FPS o limit redraws?
  • What the heck is the “when” parameter of these sorts of things? Passing in SystemClock.uptimeMillis() is the only one that worked, and trying to delay it by adding a ” + 100″ or something to fire every 100ms just made it stutter.

I’ve researched this as much as I can… I’m leaving it to StackOverflow now 🙂

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-26T04:16:34+00:00Added an answer on May 26, 2026 at 4:16 am

    After some time with the drawing board, I simplified the functions down. Essentially, it was sending an invalidate() call on every SystemClock.uptimeMillis(), doing one redraw for each step change.

    So, I removed the Drawable.Callback interface and passed the invalidateSelf() call directly from the Handler, removing the intermediary interface methods, which didn’t seem to do anything special anyway.

    There was a slight difference in the CPU usage using
    drawBitmap(Bitmap source, int X, int Y, Paint p) vs.
    drawBitmap(Bitmap source, Matrix matrix, Paint p), so I opted for the latter to save cycles.

    New methods are as follows:

    // Runnable
    mInvalidater = new Runnable(){
        @Override
        public void run(){
            // decrement the drawables step size
            mPosX -= SlidingDrawable.STEP_SIZE;
            if(Math.abs(mPosX) >= mBitmapWidth){
                mPosX = 0;
                mImageMatrix.setTranslate(0, 0);
            }
            mImageMatrix.postTranslate(-STEP_SIZE, 0);
            SlidingDrawable.this.invalidateSelf();
        }
    };
    // Draw method
    @Override
    public void draw(Canvas canvas) {
        canvas.drawBitmap(mBitmap.getBitmap(), mImageMatrix, null);
        mHandler.postAtTime(mInvalidater, SystemClock.uptimeMillis() + 64); 
    }
    

    I tested the battery results by unplugging the phone, running the application for around a minute, then opening the battery usage on my Moto Droid. Before, the battery usage surpassed the Display, now it sits comfortably below.

    Angry Birds was also a benchmark, by running the opening screen (where the bg scrolls and the birds fly everywhere) for the same amount of time, in some cases my app sat below Angry Birds, but not always.

    CPU usage was checked using the ADB shell command dumpsys cpuinfo as there seems to be a problem viewing CPU info on through the DDMS on devices running 2.2.

    I’d still be up to hear other thoughts on this, but for now, it’s solved.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I've noticed my Cucumber tests started to take a loooong time to run, and
I'm streaming videos via rtmp from Amazon Cloudfront. Videos are taking a loooong time
I'm getting the following error when trying to build my very simple webservice project.
I'm messing around with stored procedures for the first time, but can't even create
My app takes a loooong list of urls, and split it in X (where
Here are some input samples: 1, 2, 3 'a', 'b',    'c' 'a','b','c' 1, 'a',
My Zend_Json is messing up in encoding an object here. I'm encoding an associative
Is there a way to compile a .vbproj or .csproj project file directly, just
I am trying to put some loooong text into an AlertDialog. The only issue
What is the easiest way to compare strings in Python, ignoring case? Of course

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.