running an animation on a thread android - android

i am trying to run a simple button animation when the game is over
i have the following classes:
GameView
GameThread
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
boolean gameover;GameThread gamethread;
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
gameover=true;
getHolder().addCallback(this); // adding the callback (this) to the surface holder to intercept events
setFocusable(true);// make the GamePanel focusable so it can handle events
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d("TAG", "surface changed");
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gamethread=new GameThread(getHolder(),this);
gamethread.setrunning(true);
gamethread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry=true;
Log.d("TAG", "Surface destroyed entered");
while(retry){
try {
gamethread.setrunning(false);
gamethread.join();
gamethread=null;
Log.d("tag","thread is destroyed" );
if(gamethread==null){
Log.d("tag","thread is destroyed and null" );
}
retry=false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//end while
}//end method
public void update(){
if(gameover){
Button gameover_button = (Button) findViewById(R.id.gameover);
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.gameoveranimation);
gameover_button.startAnimation(animation);
}
}//end update`
public class GameThread extends Thread {
// desired fps
private boolean running;
private SurfaceHolder surfaceholder;
private GameView gameview;
public GameThread(SurfaceHolder surfaceHolder, GameView gameview){
this.gameview=gameview;
this.surfaceholder=surfaceHolder; //we need the surfaceholder since we need to lock surface before drawing
}
public void setrunning(boolean running){
this.running=running;
}
#Override
public void run(){
super.run();
Canvas canvas;
while(running){
canvas=null;
canvas = this.surfaceholder.lockCanvas();
synchronized (surfaceholder) {
if(canvas!=null){
canvas.drawColor(Color.BLACK);
this.gameview.Draw1(canvas);
this.gameview.update();
}//end if
}
}
}finally{//in case of an exception
if(canvas!=null){
surfaceholder.unlockCanvasAndPost(canvas);
}
}//end finally
}//end loop
}//end run
}
<br>
everything works fine except the animation in the update method in the gameview class
the animation runs fine in the oncreate method
i know that my problem is related to thread but i don't know much about them
thx in advance
`

If your issue is that you need to call update on the UI thread, then you can use this:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
this.gameview.update();
}
});
Also, it looks like you are looking for your game-over button as a child of your surface view. If that is not correct, you can find the view relative to the parent activity.
Activity activity = (Activity) getContext();
Button gameover_button = (Button) activity.findViewById(R.id.gameover);

Related

How to properly resume app

I'm new to Android and threading.
What app does
I have a simple app that just shows a bitmap bouncing around within the screen's boundaries (i.e. if bitmap hits the right edge of the screen, it will reverse direction).
Issue
App freezes when I minimize it and also sometimes takes a long time to load and when it loads I see a black screen.
QUESTION
Please try to run the code it is just one file shown below, I just use SurfaceView as layout. There is nothing advanced in term of what app does.
I'm confused as to why we need to use SurfaceHolder.Callback anonymous class (used in a method in the nested SurfaceView class) if there are life cycle methods I write called a pause, resume and stop in nested SurfaceView class that is called by the Main Activity's onPause, onResume, onStop methods. The entire code is shown followed by the structure of app to see an overview that I made because I don't see the point of SurfaceHolder.Callback methods so I mean I don't know why we need to use surfaceCreated, surfaceChanged, surfaceDestroyed and I don't know what to put in surfaceChanged. I also have an onSaveInstanceSate and onRestoreInstance state methods that just save the bitmap's x and y coordinates.
public class MainActivity extends Activity {
GameView gameView;
Handler myHandler;
int xPos = 0;
int yPos = 0;
int deltaX = 3;
int deltaY = 3;
int iconWidth;
int iconHeight;
static final String STATE_POS_X = "playerPosX";
static final String STATE_POS_Y = "playerPosY";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myHandler = new Handler ();
gameView = new GameView(this);
setContentView(gameView);
}
class GameView extends SurfaceView {
private SurfaceHolder surfaceHolder;
private Bitmap bmpIcon;
private MyThread myThread;
volatile boolean playingGame = true;
public GameView(Context context) {
super(context);
init();
}
public GameView(Context context,
AttributeSet attrs) {
super(context, attrs);
init();
}
public GameView(Context context,
AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init(){
myThread = new MyThread(this);
surfaceHolder = getHolder();
bmpIcon = BitmapFactory.decodeResource(getResources(),
R.drawable.rubberBall);
iconWidth = bmpIcon.getWidth();
iconHeight = bmpIcon.getHeight();
surfaceHolder.addCallback( new SurfaceHolder.Callback(){
#Override
public void surfaceCreated(SurfaceHolder holder) {
myThread.setRunning(true);
myThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
// What do I enter here???
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
myThread.setRunning(false);
while (retry) {
try {
myThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}});
}
protected void drawSomething(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bmpIcon,
getWidth()/2, getHeight()/2, null);
xPos += deltaX;
if(deltaX > 0){
if(xPos >= getWidth() - iconWidth){
deltaX *= -1;
}
}else{
if(xPos <= 0){
deltaX *= -1;
}
}
yPos += deltaY;
if(deltaY > 0){
if(yPos >= getHeight() - iconHeight){
deltaY *= -1;
}
}else{
if(yPos <= 0){
deltaY *= -1;
}
}
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bmpIcon,
xPos, yPos, null);
}
public void pause() {
playingGame = false;
try {
myThread.join();
} catch (InterruptedException e) {
}
}
public void resume() {
playingGame = true;
myThread = new MyThread(this);
myThread.start();
}
}//END INNER CLASS: GameView
class MyThread extends Thread {
GameView myView;
private boolean running = false;
public MyThread(GameView view) {
myView = view;
}
public void setRunning(boolean run) {
running = run;
}
#Override
public void run() {
while (running){
Canvas canvas = myView.getHolder().lockCanvas();
if(canvas != null) {
synchronized (myView.getHolder()) {
myView.drawSomething(canvas);
}
myView.getHolder().unlockCanvasAndPost(canvas);
}
try {
this.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//END WHILE
}
}//END INNER CLASS: MyThread
/**
* BELOW are Main Activity Life Cycle Call Back methods!
*
*/
#Override
protected void onStop() {
super.onStop();
Log.d("onStop", "Main Activity's onStop called");
while (true) {
gameView.pause();
break;
}
this.finish();
}
#Override
protected void onResume() {
super.onResume();
Log.d("onResume", "Main Activity's onResume called");
gameView.resume();
}
#Override
protected void onPause() {
super.onPause();
Log.d("onPause", "Main Activity's onPause called");
gameView.pause();
}
//save and restore state
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
// Save the user's current game state
savedInstanceState.putInt(STATE_POS_X, xPos);
savedInstanceState.putInt(STATE_POS_Y, yPos);
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
xPos = savedInstanceState.getInt(STATE_POS_X);
yPos = savedInstanceState.getInt(STATE_POS_Y);
}
}//END CLASS: MainActivity
STRUCTURE of MainActivity housing the nested SurfaceView class
MainActivity life cycle methods
--------------------------------
onCreate:
------------
-links up the layout which is the SurfaceView instance
-initialize variables
onPause:
---------
call the SurfaceView's custom pause method here in addition to calling the
super's onPause
onStop:
------
call the SurfaceView's custom stop method here in addition to calling the
super's onStop
onResume:
---------
call the SurfaceView's custom resume method here in addition to calling the
super's onResume
nested Thread class
------------------------
run method to run SurfaceView
nested class SurfaceView's life cycle methods
-------------------------------------------------------
pause method which pauses the worker thread
---------------------------------------------
stop the worker thread:
stop method which stops the worker thread:
-----------------------------------------
stop the worker thread
resume method which creates a new worker thread:
---------------------------------------------------
make a new worker thread
SurfaceHolder.Callback lifespan methods
***Why do we need to write the methods below if I have pause,
resume stop already that will be called by the Main Activity's
onXXX, respectively????
==========================================
surfaceCreated:
---------------
make a new worker thread
surfaceChanged:
---------------
What do I enter here??
surfaceDestroyed:
-----------------
destroy current worker thread
END of nested SurfaceView class
override onSaveInstanceState method:
------------------------------------
save the bitmap's position (x and y coordinates)
override onRestoreInstanceState method:
-----------------------------------------
restore the bitmap's position (x and y coordinates)
END of MainActivity
Check the very well explanation because SurfaceView is more fine tuned control of graphics unlike drawing with a Custom View or using predefined graphical inputs or GUI elems.
http://blog.infrared5.com/2011/07/android-graphics-and-animation-part-ii-animation/

Android SurfaceView IllegalArgumentException lockCanvas

I'm working on a video into a SurfaceView.
My goal is to get recurrent bitmaps of the running video.
Here is my Custom implementation:
private static final String TAG = "XXX";
private Activity activity;
private SurfaceHolder mSurface;
private MediaPlayer mMediaPlayer;
private SurfaceHolder mActiveSurface;
public ImageView imageView;
boolean locked, locked1;
private boolean isCreated;
public AlphaSurfaceView(Context context,Activity activity) {
super(context);
getHolder().addCallback(this);
setWillNotDraw(false);
this.activity = activity;
}
public AlphaSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AlphaSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
}
#Override
public void onDraw(Canvas canvas) {
//super.onDraw(canvas);
if(isCreated){
if(getHolder() != null && getHolder().getSurface().isValid()){
Canvas c = null;
try {
if(!locked){
try {
c = getHolder().lockCanvas();
locked = true;
}catch (IllegalArgumentException e){
e.printStackTrace();
locked = false;
}
BitmapDrawable bdrawable = new BitmapDrawable();
bdrawable.draw(c);
}
}catch (Exception e){
e.printStackTrace();
locked = false;
}finally {
if(c != null && locked){
getHolder().unlockCanvasAndPost(c);
locked = false;
}
}
}
}else{
super.onDraw(canvas);
}
invalidate();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mSurface = holder;
mMediaPlayer = MediaPlayer.create(getContext(), Uri.parse("XX"), mSurface);
mActiveSurface = mSurface;
try {
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mMediaPlayer.start();
mMediaPlayer.setLooping(true);
}
});
} catch (Exception e) {
e.printStackTrace();
}
this.isCreated = true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfacechanged");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mMediaPlayer.stop();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mMediaPlayer.stop();
}
The problem is an IllegalArgumentException occured by the lockCanvas() method.
I tried many possibilities as:
Adding some boolean (locked & creation of surfaceview)
Test if surface is valid
even add exported="true" in targeted activity in Manifest's xml
By the way the first idea was to use getDrawingCache() but even i added setCacheEnabled(true), the return was null.
So how to resolve this Exception or using another way to get each frame?
Thanks!
You can't draw on a Surface and send a video to it. A Surface is the producer end of a producer-consumer pair, and you can only have one producer at a time.
The easiest way to have a Canvas overlap a SurfaceView Surface is to draw on the View part of the SurfaceView. Send the video to the Surface, and use onDraw() (like a custom view) to draw on the View.
Bear in mind that the Surface is a separate layer that sits behind the View UI layer, so you will need to draw on the View with transparency to see the Surface contents.
Another approach is to use multiple overlapping SurfaceViews, but this is less efficient and more limited. An example with three overlapping Surfaces can be found in Grafika's multi-surface test Activity.
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Log.e("video","surfaceChanged");
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
Log.e("video","surfaceCreated");
mediaPlayer.setDisplay(surfaceHolder);
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.e("video","surfaceDestroyed");
if (mediaPlayer != null) mediaPlayer.release();
}
});
That should help.
Let the MediaPlayer do the drawing thing.

surface view not drawing anthing ... frame skipped message

public class CannonView extends SurfaceView implements SurfaceHolder.Callback {
CannonThread cannonThread;
private Paint blockerPaint;
public CannonView(Context context, AttributeSet attrs) {
super(context, attrs);
blockerPaint = new Paint();
blockerPaint.setStrokeWidth(10.0f);
getHolder().addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
cannonThread = new CannonThread(holder);
cannonThread.running(true);
cannonThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
cannonThread.running(false);
while (retry) {
try {
cannonThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
private class CannonThread extends Thread {
boolean setRunning;
SurfaceHolder surfaceHolder;
public CannonThread(SurfaceHolder holder) {
setRunning = true;
surfaceHolder = holder;
}
public void running(boolean isRunning) {
setRunning = isRunning;
}
#Override
public void run() {
Canvas canvas = null;
while (setRunning) {
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
canvas.drawLine(0, 0, 100, 100, blockerPaint);
}
} finally {
if (canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
Although above code is very simple
but it is not drawing anything on my activity ..
Logcat says i am doing too much work on main thread ..62 frame skipped ..
Please help
Well this isn't my style of coding, so I decided that you need to simplify things a bit. You used the android api guides but they suck.
Watch the following videos and you should be fine.
http://www.youtube.com/watch?v=wUmId0rwsBQ&list=SP2F07DBCDCC01493A&index=67
http://www.youtube.com/watch?v=0wy907WZFiA&list=SP2F07DBCDCC01493A
http://www.youtube.com/watch?v=ZMcYbf9Hhe4&list=SP2F07DBCDCC01493A
http://www.youtube.com/watch?v=yowNavIDzzE&list=SP2F07DBCDCC01493A

How can I bring to front an object in SurfaceView

Is there any way to get objects to foregorund in surfaceView.
for example:
canvas.drawBitmap(...);
canvas.drawText(...);
If I do that text appeared on bitmap. How can I reverse it without redrawing
Sorry for my English.
Canvas just encapsulates bitmap object and bitmap only saves colour of pixel at some position, it doesn't save separate layers. It's like to draw in MSPaint. So you can't change the Z-order of your primitives on canvas. However, why don't you just change the order of commands?
There is no method to bring elements front and back. You are trying to alter the Z-order of the elements here and this is not possible or there is no direct method in Android. All you can do is arrange them in the layout and enable and disable views so that it will give you the same effect.
You can use addView() or setVisibility(View.Visible) to bring bring elements back and front.
Please try to use bellow code.
//SurfaceView class
public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {
MainThread thread;
public MainGamePanel(Context context) {
super(context);
// TODO Auto-generated constructor stub
getHolder().addCallback(this);
setFocusable(true);
thread = new MainThread(getHolder(), this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
Log.e("N", "Changed");
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.e("N", "Created");
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
Log.e("N", "Destroyed");
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (event.getY() > getHeight() - 50) {
thread.setRunning(false);
((Activity) getContext()).finish();
} else {
Log.d("N", "Coords: x=" + event.getX() + ",y=" + event.getY());
}
}
return super.onTouchEvent(event);
}
}
//MainThread class
public class MainThread extends Thread {
// flag to hold game state
private boolean running;
private SurfaceHolder surfaceHolder;
private MainGamePanel gamePanel;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
long tickCount = 0L;
Log.d("N", "Starting game loop");
while (running) {
tickCount++;
// update game state
// render state to the screen
}
Log.d("N", "Game loop executed " + tickCount + " times");
}
}
//Main Activity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MainGamePanel(this));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}

OnDraw() is not fired, nothing is drawn in surfaceView - Android

HI! I have a surfaceView inside a horizontal scrollview that I want to fill with images with a onDraw() call. However, nothing is drawn.
I have a class in which the drawing is done from the thread CanvasThread.
public class PanelChart extends SurfaceView implements SurfaceHolder.Callback {
private CanvasThread canvasthread ;
public PanelChart(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
getHolder().addCallback(this);
canvasthread = new CanvasThread(getHolder(), this);
setFocusable(true);
I have tried to change the
`synchronized (_surfaceHolder) {
_panel.postInvalidate();
}`
to
synchronized (_surfaceHolder) {
_panel.postInvalidate();
}
I have also tried to add the call setWillNotDraw(false) without luck:
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
canvasthread.setRunning(true);
canvasthread.start();
setWillNotDraw(false);
This seems to be a common issue, but none of the solutions I have come across have worked for me.
Thanks!
postInvalidate will not call onDraw with surfaceView. You need to unlock canvas, draw things and then lock canvas. Here is an example of a thread for surfaceView:
class CanvasThread extends Thread {
private SurfaceHolder surfaceHolder;
private PanelChart panel;
private boolean run = false;
public CanvasThread(SurfaceHolder surfaceHolder, PanelChart panel) {
this.surfaceHolder = surfaceHolder;
this.panel = panel;
}
public void setRunning(boolean run) {
this.run = run;
}
public SurfaceHolder getSurfaceHolder() {
return surfaceHolder;
}
#Override
public void run() {
Canvas c;
while (run) {
c = null;
//limit the frame rate to maximum 60 frames per second (16 miliseconds)
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) {
panel.onDraw(c); //draw canvas
computePhysics(); //calculate next frame
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c); //show canvas
}
}//try finally
} //while
}//run
}//thread

Categories

Resources