Galaxy Nexus slow with animation

I edited this code to migrate Rect instances from the onDraw method. I tested it on several devices.

public class BallBouncesActivity extends Activity { BallBounces ball; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ball = new BallBounces(this); setContentView(ball); } } class BallBounces extends SurfaceView implements SurfaceHolder.Callback { GameThread thread; int screenW; //Device screen width. int screenH; //Devices screen height. int ballX; //Ball x position. int ballY; //Ball y position. int initialY ; float dY; //Ball vertical speed. int ballW; int ballH; int bgrW; int bgrH; int angle; int bgrScroll; int dBgrY; //Background scroll speed. float acc; Bitmap ball, bgr, bgrReverse; boolean reverseBackroundFirst; boolean ballFingerMove; Rect toRect1, fromRect1; Rect toRect2, fromRect2; //Measure frames per second. long now; int framesCount=0; int framesCountAvg=0; long framesTimer=0; Paint fpsPaint=new Paint(); //Frame speed long timeNow; long timePrev = 0; long timePrevFrame = 0; long timeDelta; public BallBounces(Context context) { super(context); ball = BitmapFactory.decodeResource(getResources(), R.drawable.rocket); //Load a ball image. bgr = BitmapFactory.decodeResource(getResources(), R.drawable.sky_bgr); //Load a background. ballW = ball.getWidth(); ballH = ball.getHeight(); toRect1 = new Rect(0, 0, bgr.getWidth(), bgr.getHeight()); fromRect1 = new Rect(0, 0, bgr.getWidth(), bgr.getHeight()); toRect2 = new Rect(0, 0, bgr.getWidth(), bgr.getHeight()); fromRect2 = new Rect(0, 0, bgr.getWidth(), bgr.getHeight()); //Create a flag for the onDraw method to alternate background with its mirror image. reverseBackroundFirst = false; //Initialise animation variables. acc = 0.2f; //Acceleration dY = 0; //vertical speed initialY = 100; //Initial vertical position angle = 0; //Start value for the rotation angle bgrScroll = 0; //Background scroll position dBgrY = 1; //Scrolling background speed fpsPaint.setTextSize(30); //Set thread getHolder().addCallback(this); setFocusable(true); } @Override public void onSizeChanged (int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //This event-method provides the real dimensions of this custom view. screenW = w; screenH = h; bgr = Bitmap.createScaledBitmap(bgr, w, h, true); //Scale background to fit the screen. bgrW = bgr.getWidth(); bgrH = bgr.getHeight(); //Create a mirror image of the background (horizontal flip) - for a more circular background. Matrix matrix = new Matrix(); //Like a frame or mould for an image. matrix.setScale(-1, 1); //Horizontal mirror effect. bgrReverse = Bitmap.createBitmap(bgr, 0, 0, bgrW, bgrH, matrix, true); //Create a new mirrored bitmap by applying the matrix. ballX = (int) (screenW /2) - (ballW / 2) ; //Centre ball X into the centre of the screen. ballY = -50; //Centre ball height above the screen. } //*************************************** //************* TOUCH ***************** //*************************************** @Override public synchronized boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { ballX = (int) ev.getX() - ballW/2; ballY = (int) ev.getY() - ballH/2; ballFingerMove = true; break; } case MotionEvent.ACTION_MOVE: { ballX = (int) ev.getX() - ballW/2; ballY = (int) ev.getY() - ballH/2; break; } case MotionEvent.ACTION_UP: ballFingerMove = false; dY = 0; break; } return true; } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); //Draw scrolling background. fromRect1.set(0, 0, bgrW - bgrScroll, bgrH); toRect1.set(bgrScroll, 0, bgrW, bgrH); fromRect2.set(bgrW - bgrScroll, 0, bgrW, bgrH); toRect2.set(0, 0, bgrScroll, bgrH); // Rect fromRect1 = new Rect(0, 0, bgrW - bgrScroll, bgrH); // Rect toRect1 = new Rect(bgrScroll, 0, bgrW, bgrH); // // Rect fromRect2 = new Rect(bgrW - bgrScroll, 0, bgrW, bgrH); // Rect toRect2 = new Rect(0, 0, bgrScroll, bgrH); if (!reverseBackroundFirst) { canvas.drawBitmap(bgr, fromRect1, toRect1, null); canvas.drawBitmap(bgrReverse, fromRect2, toRect2, null); } else{ canvas.drawBitmap(bgr, fromRect2, toRect2, null); canvas.drawBitmap(bgrReverse, fromRect1, toRect1, null); } //Next value for the background position. if ( (bgrScroll += dBgrY) >= bgrW) { bgrScroll = 0; reverseBackroundFirst = !reverseBackroundFirst; } //Compute roughly the ball speed and location. if (!ballFingerMove) { ballY += (int) dY; //Increase or decrease vertical position. if (ballY > (screenH - ballH)) { dY=(-1)*dY; //Reverse speed when bottom hit. } dY+= acc; //Increase or decrease speed. } //Increase rotating angle if (angle++ >360) angle =0; //DRAW BALL //Rotate method one /* Matrix matrix = new Matrix(); matrix.postRotate(angle, (ballW / 2), (ballH / 2)); //Rotate it. matrix.postTranslate(ballX, ballY); //Move it into x, y position. canvas.drawBitmap(ball, matrix, null); //Draw the ball with applied matrix. */// Rotate method two canvas.save(); //Save the position of the canvas matrix. canvas.rotate(angle, ballX + (ballW / 2), ballY + (ballH / 2)); //Rotate the canvas matrix. canvas.drawBitmap(ball, ballX, ballY, null); //Draw the ball by applying the canvas rotated matrix. canvas.restore(); //Rotate the canvas matrix back to its saved position - only the ball bitmap was rotated not all canvas. //*/ //Measure frame rate (unit: frames per second). now=System.currentTimeMillis(); canvas.drawText(framesCountAvg+" fps", 40, 70, fpsPaint); framesCount++; if(now-framesTimer>1000) { framesTimer=now; framesCountAvg=framesCount; framesCount=0; } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { thread = new GameThread(getHolder(), this); thread.setRunning(true); thread.start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; thread.setRunning(false); while (retry) { try { thread.join(); retry = false; } catch (InterruptedException e) { } } } class GameThread extends Thread { private SurfaceHolder surfaceHolder; private BallBounces gameView; private boolean run = false; public GameThread(SurfaceHolder surfaceHolder, BallBounces gameView) { this.surfaceHolder = surfaceHolder; this.gameView = gameView; } public void setRunning(boolean run) { this.run = run; } public SurfaceHolder getSurfaceHolder() { return surfaceHolder; } @Override public void run() { Canvas c; while (run) { c = null; //limit frame rate to max 60fps timeNow = System.currentTimeMillis(); timeDelta = timeNow - timePrevFrame; if ( timeDelta < 16) { try { Thread.sleep(16 - timeDelta); } catch(InterruptedException e) { } } timePrevFrame = System.currentTimeMillis(); try { c = surfaceHolder.lockCanvas(null); synchronized (surfaceHolder) { //call methods to draw and process next fame gameView.onDraw(c); } } finally { if (c != null) { surfaceHolder.unlockCanvasAndPost(c); } } } } } } 

If you notice, there is a code for measuring frame rate:

  now=System.currentTimeMillis(); canvas.drawText(framesCountAvg+" fps", 40, 70, fpsPaint); framesCount++; if(now-framesTimer>1000) { framesTimer=now; framesCountAvg=framesCount; framesCount=0; } 

I see that on both of my Galaxy Nexus devices running Android 4.0 and 4.2, it is 22-24 frames per second. On my HTC Desire running Android 2.2, it looks more like 60 frames per second.

You will also notice that I do not highlight anything in the onDraw method. I also do not create new Paint objects. I really don’t understand how this works, therefore, it is so slower on my Galaxy Nexus devices. There is a lot of stuttering, and the ball moves very slowly.

Does anyone know if there is a setting that I can cancel, or a known issue with re-drawing on the Galaxy Nexus? This happens with my Galaxy Nexus that runs 4.0 and the one that runs 4.2, so I'm not sure if it depends on the OS. I disabled the window and transition animation in the developer settings. Do I affect two-dimensional acceleration.

+7
source share
4 answers

I thought about this, since I'm still having performance problems on my Nexus 10 with a surface overview, as I said earlier, I significantly increased my productivity by removing the use of objects for painting, this is a long shot as you use only one. but you can try to remove the section of the text drawing from your onDraw () just to see if the speed of your drawing matters.

Other than that, I think this is really an attempt to try to solve the problem.

I noticed that even if I completely remove my onDraw and Logic update methods from the equation, it still sometimes takes up to 25 ms only to lock and unlock / publish the canvas! Perhaps the problem is not in the onDraw method, but in the Run () method, as well as what speeds you get (use logging for Logcat to see the numbers, remember that, ironically, displaying the frame / time on the screen can affect on what you are measuring). :-)

0
source

Have you tested the android: hardwareAccelerated = "true | false" in the application?

Android Dev Doc: http://developer.android.com/guide/topics/graphics/hardware-accel.html

You can add before setContentView:

 if (android.os.Build.VERSION.SDK_INT >= 11) { getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); } 
+1
source

What did your targetSdk install?

If targetSdk is set to 8 (2.2), but you use it on device 4.x (15+), device 4.x will work in compatibility mode, which means that it will virtualize all calls, that they will return exactly the same as if they were running on a version 8 device.

This virtualization may explain some slowness. Try changing targetSdk to 17 (for your 4.2 device) and see if it has changed.

0
source

I experienced the same thing on Kindle Fire, Sony Xperia Z and Samsung S4 (all with Android 4.0).

Bugfix: in the application manifest file, delete "android: supportsRtl =" true "".

Hope this saves you some time. I spend 4 hours on tests and mergers before I get them.

0
source

All Articles