-1

I've started the development of a guitar application, and am stuck on a graphical aspect. My screen contains a background image, which you can move with 2 fingers, by sliding up or down. My background image, a bitmap, moves at low fps on an android device. I'm looking to see how to make it run smoother.

Code details: I have 3 classes: one main activity, a second for graphics, and a third as a splash screen (I have't included the last one as it has nothing to do with my problems).

MainActivity.java

package com.example.androidapplication;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;


public class MainActivity extends Activity implements OnTouchListener{

    FretBoard ourView;
    float y1, y2, dy;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        ourView = new FretBoard(this);
        ourView.setOnTouchListener(this);
        setContentView(ourView);

    }

    //Method to be used in future
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        ourView.pause();
    }

    //Method to be used in future
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        ourView.resume();
    }



    @Override
    public boolean onTouch(View v, MotionEvent event){

        //For debugging
        if(event!= null) ourView.fingerCount = event.getPointerCount();

        switch(event.getAction()){

            case MotionEvent.ACTION_DOWN:

                //Save first y position when finger touches screen
                y1 = event.getY();

                break;


            case MotionEvent.ACTION_MOVE:

                if(event != null && event.getPointerCount() == 2){

                    //Save second y position when finger moves
                    y2 = event.getY();

                    //Total distance moved
                    dy = y2 - y1;
                    if((ourView.bgY + dy)<0) ourView.bgY += dy/2;

                    //For Debugging
                    System.out.println("Y1 : " + y1 + "     Y2 : " + y2                +   "   DY : " + dy);

                    //Redraw the Screen 
                    ourView.invalidate();

                    //Reset y1 
                    y1 = y2;
                }

                break;
        }
        return true;
    }

}

FretBoard.java

package com.example.androidapplication;

import java.io.InputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


public class FretBoard extends SurfaceView implements Runnable{

    //Background image variables
    Bitmap background;
    InputStream is = getResources().openRawResource(R.drawable.fret_board);

    //Debugger text variables
    Paint mPaint = new Paint();
    String string = "Fingers: ";
    int fingerCount = 0;

    //Position Variables
    int width, height;
    float bgY = 0, bgX = 0;

    //Holder variable
    SurfaceHolder ourHolder;

    //To be used in future
    Thread ourThread = null;
    Boolean isRunning = false;

    public FretBoard(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        ourHolder = getHolder();
        ourThread = new Thread(this);
        ourThread.start();

    }

    //To be used in the future
    public void pause(){
        isRunning = false;
        while(true){
            try {
                ourThread.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            break;
        }
        ourThread = null;
    }

    //To be used in the future
    public void resume(){
        isRunning = true;
        ourThread = new Thread(this);
        ourThread.start();
    }


    //Creates a InputStream to set width, then converts to bitmap to be
    //drawn as background on the canvas.
    public Bitmap bmScale(InputStream is){
       BitmapFactory.Options o = new BitmapFactory.Options();
       o.inSampleSize = 2;
       Bitmap bit = BitmapFactory.decodeStream(is, null, o);
       background = Bitmap.createScaledBitmap(bit, width, 2300, true);
       bit.recycle();
       return background;
    }


    //This is the draw method where I need help
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(isRunning){
            if(!ourHolder.getSurface().isValid()) continue;

            //Lock canvas to draw 
            Canvas canvas = ourHolder.lockCanvas();

            //Do Things Here:
            width = getWidth();
            height = getHeight();

            //Collision detection for the background
            if(bgY > 0 ) bgY = 0;

            //Draws the background
            bmScale(is);
            canvas.drawBitmap(background, bgX, bgY, null);

            //For debugging, displays the number of fingers on the screen
            canvas.drawText(string + fingerCount, 50, 50, mPaint);

            //Unlock canvas to show 
            ourHolder.unlockCanvasAndPost(canvas);
        }
    }   
}
Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
user2116613
  • 11
  • 1
  • 1
  • 2
    do you think more people will help if you are a female? – Kailua Bum Feb 27 '13 at 18:50
  • 1
    More generally, use Traceview to determine where you are spending your time, so you know what needs fixing. – CommonsWare Feb 27 '13 at 20:12
  • For possible next questions, try to provide only information that is relevant to your question. Being female or being (self proclaimed) proficient in something can be omitted. – Bart Kiers Feb 27 '13 at 23:00

2 Answers2

3

It seems you are loading/reading and scaling the bitmap on each render pass. This is enormously inefficient. (see call to bmScale(is); in FretBoard.java).

Instead, load (and scale your) bitmap only once (when the view gets laid out) and then draw the already loaded and scaled bitmap.

Also, you seem to use a SurfaceView for your FretBoard. Why? In your code sample, you are not using OpenGL or Video/Camera textures at all.

Streets Of Boston
  • 12,576
  • 2
  • 25
  • 28
  • There's nothing wrong with `SurfaceView` for something simple like this. It seems like there's very little real animation, so the performance differences shouldn't be terrible. Your comment on scaling is spot on though. – kabuko Feb 27 '13 at 19:24
0

Scaling in your loop (as mentioned by the other answer here) is definitely your major problem. Once you fix that, things should be much smoother. You will probably find some minor stutters still though because you are creating other objects in your loop, namely strings. Given that you will never have more than 5 fingers on the fretboard at once (OK, maybe theoretically 10 if you're tapping) there are only 5 or 10 possible values for string (which by the way is a confusing name, especially in this context). It'd be better to create these up front as well outside of the loop and just pick the correct reference.

kabuko
  • 36,028
  • 10
  • 80
  • 93