When testing several games with a standard game thread in Android 4.0 it works well until the Activity is shut down (pressing the home button etc), leaving the activity the application crashes with a nullPointer.
This even happens in the sample LunarLander that Google has programmed.
The problem is that Canvas becomes null when leaving the activity and that makes the application crash.
The error message from the LogCat is just below.
02-27 18:07:58.974: V/MainThread(2667): CANVAS android.view.Surface$CompatibleCanvas#4102bcf0
02-27 18:07:59.164: V/MainThread(2667): CANVAS null
02-27 18:07:59.164: W/dalvikvm(2667): threadid=14: thread exiting with uncaught exception (group=0x409c01f8)
02-27 18:07:59.174: E/AndroidRuntime(2667): FATAL EXCEPTION: Thread-108
02-27 18:07:59.174: E/AndroidRuntime(2667): java.lang.NullPointerException
02-27 18:07:59.174: E/AndroidRuntime(2667): at com.joakimengstrom.pong.MainThread.run(MainThread.java:49)
This is the code when starting a thread, with the Log.v you see above.
while(this.running){
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
Log.v(TAG, "CANVAS " + canvas);
canvas.drawColor(Color.BLACK);
...
And below is when creating the thread and shutting it down when the surface is destroyed.
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new MainThread(getHolder());
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) {
}
}
}
How do I exit the thread in a safe way without making canvas null?
In Android 4.0, SurfaceHolder.lockCanvas can return null when the surface is destroyed. So here:
try {
canvas = this.surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
Log.v(TAG, "CANVAS " + canvas);
canvas.drawColor(Color.BLACK);
Just surround your synchronized (surfaceHolder) block with if (canvas != null). This should not cause any issues with the behaviour of your application as it occurs when drawing is not needed.
Related
In my game, I have a thread. This thread is paused in onPause() in the activity and restarted in surfaceCreated in the main game class.
#Override
public void surfaceCreated(SurfaceHolder holder) {
if(gt == null) {
gt = new GameThread(getHolder(), this);
gt.setRunning(true);
gt.start();
}
}
The onPause(called from game):
public void onPause(){
... other stuff
if(gt != null){
try {
gt.setRunning(false);
gt.join();
gt = null;
}catch(Exception e){
e.printStackTrace();
}
}
}
But for some reason, when the screen is locked and unlocked, the thread does not start again. When I open the list of recent apps and reopen the app from there, the thread restarts.
Why is this happening, and how can I solve it?
You should start your thread in onStart(), not in surfaceCreated, because the surface is not recreated in this case (your activity is not destroyed), so the method surfaceCreated is not called when you unlock your phone. However, onStart() is.
Please scroll down to the "EDIT" :)
I'm trying to understand some basic android animation programming using Android Studio, and I have followed some tutorials on the internet.
I already know some basic java programming, but I have a problem with my "copy/paste app" I made.
This is my MainActivity:
public class MainActivity extends ActionBarActivity {
private Button play;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
play = (Button) findViewById(R.id.play_button);
play.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent startGame = new Intent("com.abc.test.DRAWGAME2");
startActivity(startGame);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}}
This is DrawGame2.java:
public class DrawGame2 extends Activity implements View.OnTouchListener {
private MyView surfaceView;
private float y;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
surfaceView = new MyView(this);
surfaceView.setOnTouchListener(this);
setContentView(surfaceView);
}
#Override
protected void onPause() {
super.onPause();
surfaceView.pause();
}
#Override
protected void onResume() {
super.onResume();
surfaceView.resume();
}
#Override
public boolean onTouch(View v, MotionEvent me) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
switch (me.getAction()){
case MotionEvent.ACTION_DOWN:
y = me.getY();
break;
case MotionEvent.ACTION_UP:
y = me.getY();
break;
case MotionEvent.ACTION_MOVE:
y = me.getY();
break;
}
return true;
}
public class MyView extends SurfaceView implements Runnable {
private Thread thread = null;
private SurfaceHolder holder;
private boolean isRunning = false;
public MyView(Context context) {
super(context);
holder = getHolder();
y = 0;
}
public void run() {
while (isRunning) {
if (!holder.getSurface().isValid()) {
continue;
}
Canvas canvas = holder.lockCanvas();
canvas.drawRGB(02,02,150);
if (y != 0){
Bitmap test = BitmapFactory.decodeResource(getResources(),R.drawable.greenball);
canvas.drawBitmap(test, canvas.getWidth()/2 - test.getWidth()/2, y, null);
}
holder.unlockCanvasAndPost(canvas);
}
}
public void pause() {
isRunning = false;
while (true) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
thread = null;
}
public void resume() {
isRunning = true;
thread = new Thread(this);
thread.start();
}
}}
Logcat:
02-12 11:01:06.676 1972-1972/com.abc.test I/art﹕ Not late-enabling -Xcheck:jni (already on)
02-12 11:01:06.881 1972-1990/com.abc.test D/OpenGLRenderer﹕ Render dirty regions requested: true
02-12 11:01:06.882 1972-1972/com.abc.test D/﹕ HostConnection::get() New Host Connection established 0xa686fb60, tid 1972
02-12 11:01:06.917 1972-1972/com.abc.test D/Atlas﹕ Validating map...
02-12 11:01:07.007 1972-1990/com.abc.test D/﹕ HostConnection::get() New Host Connection established 0xa686fd90, tid 1990
02-12 11:01:07.037 1972-1990/com.abc.test I/OpenGLRenderer﹕ Initialized EGL, version 1.4
02-12 11:01:07.102 1972-1990/com.abc.test D/OpenGLRenderer﹕ Enabling debug mode 0
02-12 11:01:07.126 1972-1990/com.abc.test W/EGL_emulation﹕ eglSurfaceAttrib not implemented
02-12 11:01:07.126 1972-1990/com.abc.test W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa6814940, error=EGL_SUCCESS
02-12 11:01:07.705 1972-1990/com.abc.test W/EGL_emulation﹕ eglSurfaceAttrib not implemented
02-12 11:01:07.705 1972-1990/com.abc.test W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa6814940, error=EGL_SUCCESS
02-12 11:01:12.571 1972-1990/com.abc.test W/EGL_emulation﹕ eglSurfaceAttrib not implemented
02-12 11:01:12.571 1972-1990/com.abc.test W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa5a69ba0, error=EGL_SUCCESS
02-12 11:01:16.892 1972-1972/com.abc.test I/Choreographer﹕ Skipped 263 frames! The application may be doing too much work on its main thread.
02-12 11:01:16.899 1972-2270/com.abc.test D/﹕ HostConnection::get() New Host Connection established 0xa5dfcc10, tid 2270
The problem with this app is that the animation is really laggy, and I can't figure out why!
I have tried to make the same animation with a simple rectangle, but the lag is still there.
The problem isn't the OnTouchListener, because I've tried to just increase the y value by 1 with each loop in the run method (while disabling the OnTouchListener), but it is still lagging.
I have tried with different emulators (Lollipop, Kitkat) and on my Samsung Galaxy S3 (Jelly Bean).
Are there any wise people out there that can help me with this problem? :)
Have a great day!
EDIT:
Okay, so I applied the answers I got, and now it runs smoothly, ON MY Samung Galaxy S3!
The lagging is still there on my emulator though. I've installed HAXM and the emulator runs smoothly out of the app I've created, but as soon as I launch the app and press the "PLAY" button, the animation lags when I interact with the app.
This is the properties for my emulator:
Name: Nexus_5_API_21
CPU/ABI: Intel Atom (x86)
hw.gpu.enabled: yes
Path: C:\Users\User\.android\avd\Nexus_5_API_21.avd
Target: Android 5.0.1 (API level 21)
Skin: nexus_5
SD Card: 100M
Snapshot: no
hw.lcd.density: 480
hw.dPad: no
avd.ini.encoding: UTF-8
hw.camera.back: none
disk.dataPartition.size: 200M
runtime.network.latency: none
skin.dynamic: no
hw.keyboard: yes
runtime.network.speed: full
hw.device.hash2: MD5:2fa0e16c8cceb7d385183284107c0c88
hw.ramSize: 1536
tag.id: default
tag.display: Default
hw.sdCard: yes
hw.device.manufacturer: Google
hw.mainKeys: no
hw.accelerometer: yes
hw.trackBall: no
hw.device.name: Nexus 5
hw.sensors.proximity: yes
hw.battery: yes
AvdId: Nexus_5_API_21
hw.sensors.orientation: yes
hw.audioInput: yes
hw.camera.front: none
hw.gps: yes
avd.ini.displayname: Nexus 5 API 21
snapshot.present: no
vm.heapSize: 64
runtime.scalefactor: auto
As far as I can see, your problem is in the onTouch() method, in which you have this code:
try{
Thread.sleep(50);
}catch (InterruptedException e){
e.printStackTrace();
}
Which will sleep the MAIN thread, meaning that everything will make the entire application hold up for 50 milliseconds.
So try to remove that.
Decoding resources are also not performance friendly. You should decode bitmap earlier and reuse it while drawing. Why you do not use onDraw method ?
So I have an app that uses a surface view that runs a separate thread for the UI. It was taken almost directly from the Lunar Landing sample app. The app also uses Bluetooth service on another thread but I am sure that this is not related to the problem because I can disable bluetooth all together and it still happens.
The problem in my app is that the app when closed and then reopened does not start running the UI thread afterthread.start() except it throws an error. In the Lunar example they have thread.start() in the onSurfaceCreated method. The problem is when I restart my app (it calls onPause then onSurfaceDestroy) the thread is already running and I get an error when I try to start it. My code for onSurfaceCreated, onPause, onResume and onSurfaceDestroyed is all the same as the example. I know I can use if (this.getState() == Thread.State.NEW) { but that seems like it will mask some of my other issues. I want to master the activity life cycle.
My question is how does the Lunar Lander stop the thread? And why is mine not stopping with the same code and running at the onSurfaceCreated method. Obviously I am missing something. As far as I know in the Lunar example the only thing that is called on the thread on a destroy is thread.join().
Edit 3: Here is the Lunar Lander Example Code if needed.
So these are the three override methods in my surfaceview...
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.d(TAG, "surfaceCreated");
// start the bluetooth service
thread.startBluetoothService();
// start the game
//if (this.getState() == Thread.State.NEW) {
Log.d(TAG, "thread start");
// start running the thread
this.start();
//}
Log.d(TAG, "running to true");
// release the thread lock
setRunning(true);
}
// surfaceChanged is called at least once after surfaceCreated
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfaceChanged");
// reset the surface size
thread.setSurfaceSize(width, height);
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.d(TAG, "surfaceDestroyed");
// make sure to shut down the thread cleanly
boolean retry = true;
// stop the running thread
thread.setRunning(false);
// continuously try to shut down the thread
while (retry){
try{
// blocks calling thread until termination
thread.join();
// stop the bluetooth service
//thread.stopBluetoothService();
retry = false;
}catch(InterruptedException e){
//try to shut it down again
}
}
}
I am really pretty lost with all of this. Any help would be very appreciated, thanks!
Edit:
So I did a little more testing. When the user hits home(which exits the app completely) onPause, then onSurfaceDestroy like I said before. Then when it restarts I get onResume followed by onSurfaceCreated. I think my issue is that it is not calling onCreate when you reenter the app.
Some more questions...
What distinguishes the difference between a onPause and a onDestroy? I think my problem is that since onCreate is not being called I don't have a newly created UI thread which seems like it is still running.
Should the thread be stopped even on a onPause? Because then I am not garenteed to run onCreate which re instantiates the thread. Here is the onCreate code...
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wobble);
// get view and thread
wobbleView = (WobbleView) findViewById(R.id.wobble);
wobbleThread = wobbleView.getThread();
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
// alert the user of bluetooth failure
Toast.makeText(this, "Bluetooth is not available, using internal devices sensors", Toast.LENGTH_LONG).show();
// set the data source to internal sensors - so we'll just use the devices accel
wobbleThread.setDataSource(WobbleThread.INTERNAL_SENSORS);
// bluetooth is supported so make sure its enabled and
}else{
// make sure bluetooth is enabled on the device
if (!mBluetoothAdapter.isEnabled()) {
Log.d(TAG, "starting request to enable bluetooth");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
// all is well with bluetooth - use bluetooth
Log.d(TAG, "setting bluetooth to bluetooth");
wobbleThread.setDataSource(WobbleThread.BLUETOOTH);
}
// give the LunarView a handle to the TextView used for messages
wobbleView.setTextView(
(TextView) findViewById(R.id.text_accel),
(TextView) findViewById(R.id.game_msg),
(TextView) findViewById(R.id.text_score),
(TextView) findViewById(R.id.bluetooth_status)
);
if (savedInstanceState == null) {
// we were just launched: set up a new game
//wobbleThread.setState(wobbleThread.STATE_READY);
} else {
//wobbleThread.setRunning(true);
// we are being restored: resume a previous game
//wobbleThread.restoreState(savedInstanceState);
}
}
Edit 2:
Some logcat output
So this is what I get when the thread.start() is called after reopening the app.
11-18 22:50:44.104 4868-4868/com.bme.shawn.wobble E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.IllegalThreadStateException: Thread already started
at java.lang.Thread.checkNotStarted(Thread.java:871)
at java.lang.Thread.start(Thread.java:1025)
at com.bme.shawn.wobble.WobbleThread.startGame(WobbleThread.java:213)
at com.bme.shawn.wobble.WobbleView.surfaceCreated(WobbleView.java:94)
at android.view.SurfaceView.updateWindow(SurfaceView.java:580)
at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:240)
at android.view.View.dispatchWindowVisibilityChanged(View.java:7903)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1289)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1050)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5750)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:561)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:150)
at android.app.ActivityThread.main(ActivityThread.java:5406)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
And if I use the thread.getState check and bypass the error I get this when I close then reopen the app. (logs in basically everything) In this case when the app reopens the thread is not drawing at all. Which is very weird since without the check I get an error saying that the thread is already running.
11-18 22:59:13.444 5345-5345/com.bme.shawn.wobble D/WobbleActivity﹕ onPause
11-18 22:59:13.584 5345-5345/com.bme.shawn.wobble D/WobbleView﹕ surfaceDestroyed
11-18 22:59:17.794 5345-5345/com.bme.shawn.wobble D/WobbleActivity﹕ onResume
11-18 22:59:17.804 5345-5345/com.bme.shawn.wobble D/WobbleView﹕ surfaceCreated
11-18 22:59:17.804 5345-5345/com.bme.shawn.wobble D/WobbleThread﹕ running to true
11-18 22:59:17.804 5345-5345/com.bme.shawn.wobble D/WobbleView﹕ surfaceChanged
11-18 22:59:17.804 5345-5345/com.bme.shawn.wobble D/WobbleThread﹕ setting surface sizes
11-18 22:59:17.824 5345-5345/com.bme.shawn.wobble D/dalvikvm﹕ GC_FOR_ALLOC freed 3343K, 2% free 6585K/6668K, paused 13ms, total 13ms
11-18 22:59:17.844 5345-5345/com.bme.shawn.wobble E/IMGSRV﹕ :0: PVRDRMOpen: TP3, ret = 44
11-18 22:59:17.854 5345-5345/com.bme.shawn.wobble E/IMGSRV﹕ :0: PVRDRMOpen: TP3, ret = 50
Create a new instance of the thread in surfaceCreated() and start it. And call thread.join() in surfaceDestroyed()to destroy it.
Background
I have created a game loop to run the UI, but when I push the back button from the game screen (SingleGameActivity) I get to the level-selector menu called (StartLvlActivity). If I try to reenter the game or push the back button from StartLvlActivity I get a keyDispatchingTimedOut error (ANR).
When I wrote Log messages, the game activity (SingleGameActivity) was only paused, not stopped when I pushed the back button. And the game loop was never destroyed when I closed the activity.
08-03 09:56:12.130: I/Process(346): Sending signal. PID: 5763 SIG: 3
08-03 09:56:12.130: I/dalvikvm(5763): threadid=3: reacting to signal 3
08-03 09:56:12.333: I/dalvikvm(5763): Wrote stack traces to '/data/anr/traces.txt'
08-03 09:56:12.341: E/ActivityManager(346): ANR in com.coderogden.pongtennis (com.coderogden.pongtennis/.activities.StartLvlActivity)
08-03 09:56:12.341: E/ActivityManager(346): Reason: keyDispatchingTimedOut
Questions
1. Why isn't the game loop destroyed when I push the back button from the game menu? I mean, why isn't surfaceDestroyed called when onPaused is called (onStop is never called and I don't know why....).
How do I access "/data/anr/traces.txt"
How do I handle the errors?
If you can answer any of these questions I would appreciate it very much!
EDIT
This is the surface view class from where I start and destroy the thread (or apperently I'm just starting it as it won't shut down when I press "back"-button).
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
Log.d(TAG, " surface created");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d(TAG, " surface destroyed");
}
EDIT 2 (with solution!)
The bug was fixed by changing this piece of code:
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
to this:
thread.setRunning(false);
WHY?
Is it because I need to stop the thread before destroying it?
I keep getting this black screen when ever I open my app, the only way to get rid of it is to press the back button, then again go to the app. I was told by my friend that it is going into deadlock! but I do not think because when I checked the logcat it shows the below log messages.
View
private boolean mGameIsRunning;
public void surfaceCreated(SurfaceHolder holder) {
// Your own start method.
start();
}
public void start() {
if (!mGameIsRunning) {
thread.initLevel();
thread.setRunning(true);
thread.start();
mGameIsRunning = true;
} else {
thread.onResume();
thread.initLevel();
thread.setRunning(true);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Surface is being destroyed");
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d(TAG, "Thread was shut down cleanly");
}
Thread
private Object mPauseLock = new Object();
private boolean mPaused;
#Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
mStartTime = System.currentTimeMillis();
mElapsedTime = System.currentTimeMillis() - mStartTime;
this.updateGame();
this.onDraw(canvas);
}
synchronized(mPauseLock){
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
Log
07-08 17:24:41.735: DEBUG/Hitman(3221): View added
07-08 17:24:41.895: DEBUG/(3221): Enemies Spawed
07-08 17:24:41.934: DEBUG/(3221): Starting game loop
07-08 17:24:42.165: INFO/ActivityManager(66): Displayed activity com.android.hitmanassault/.Hitman: 1384 ms (total 1384 ms)
07-08 17:24:46.164: DEBUG/(3221): Enemies Spawed
07-08 17:24:48.914: INFO/ActivityManager(66): Start proc com.android.settings for broadcast com.android.settings/.widget.SettingsAppWidgetProvider: pid=3228 uid=1000 gids={3002, 3001, 3003}
07-08 17:24:48.914: INFO/ActivityManager(66): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.android.launcher/.Launcher }
07-08 17:24:48.924: DEBUG/PhoneWindow(3221): couldn't save which view has focus because the focused view com.android.hitmanassault.HitmanView#44d99528 has no id.
07-08 17:24:48.954: INFO/WindowManager(66): Setting rotation to 0, animFlags=0
07-08 17:24:49.014: INFO/ActivityManager(66): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/2 nav=3/1 orien=1 layout=34}
07-08 17:24:49.275: DEBUG/(3221): Surface is being destroyed
07-08 17:24:49.285: DEBUG/(3221): Thread was shut down cleanly
07-08 17:24:49.694: DEBUG/ddm-heap(3228): Got feature list request
07-08 17:24:49.754: WARN/IInputConnectionWrapper(3221): showStatusIcon on inactive InputConnection
07-08 17:24:51.315: DEBUG/dalvikvm(66): GC freed 2325 objects / 114696 bytes in 122ms
07-08 17:24:58.234: INFO/ActivityManager(66): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.hitmanassault/.HitmanTitle }
07-08 17:24:58.284: INFO/WindowManager(66): Setting rotation to 1, animFlags=0
07-08 17:24:58.354: INFO/ActivityManager(66): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/2 nav=3/1 orien=2 layout=34}
07-08 17:24:58.554: DEBUG/(3221): Enemies Spawed
07-08 17:24:58.945: WARN/IInputConnectionWrapper(144): showStatusIcon on inactive InputConnection
07-08 17:25:00.604: DEBUG/dalvikvm(66): GC freed 1403 objects / 71832 bytes in 103ms
Activity Class:
#Override
public boolean onCreateOptionsMenu(Menu menu){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item){
switch(item.getItemId()){
case R.id.menu_restart:
startActivity(new Intent(this, Hitman.class));
return true;
case R.id.menu_scores:
startActivity(new Intent(this, HitmanScores.class));
return true;
case R.id.menu_help:
startActivity(new Intent(this, HitmanHelp.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new CanvasSurfaceView(this));
Log.d(TAG, "View added");
}
Does rotating the display cause it to refresh (in emulator: CTRL+F12)? If so then you have to override onResume() in your activity and have it restart whatever it is you set up that might not be being called. It could be that you just need to call view.invalidate() from the activity onResume()? You don't show code from your activity so I'm unsure.
In the code I saw, you should use this.postInvalidate() (same as invalidate() but for from a different thread) instead of this.onDraw(canvas) and have it call this.onDraw() on its own in the UI thread, as opposed to in your thread.
Where do you initialize your thread? Try doing so in surfaceCreated( ) instead of the surfaceView consturctor (which is where I think you did it..)
public void surfaceCreated(SurfaceHolder holder) {
// Restart draw thread
Thread.State state = thread.getState();
if(state == Thread.State.TERMINATED)
thread = new MyThread(getHolder(), getContext());
thread.setRunning(true);
thread.start();
}