Hi Robert,
Great Website!!
I've started programming for Android two weeks ago.
I've read an awful lot about java & android (I had much experience with other languages but not java and not game development).
After the "Hello Android" example I started my own Tetris clone as a practice.
I have created the game as SplashActivity -> MenuActivity -> GameActivity -> GameView -> GameThread. (start with a splash screen, than show a menu with a button for starting the game)
The game itself went fairly smooth but I run into problems now that I want to improve it. I tun into problem openeing an AlertDialog from my GameThread. E.g. used for entering your name when you have a high-score, or just selection if you want to restart / quit the game.
The first issue I ran into is the error message about the looper:
E/AndroidRuntime( 1359): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I can bypass / solve(?) this by using the following statements because it is an additional Thread besides the UI thread (inside my 'run' method just as a test):
Looper.prepare();
Looper.loop();
Looper.myLooper().quit();
After adding those looper lines I'm able able to open a dialog by using alertdialog.builder. Unfortunately as soon as I select a positive/negative/neutral button my dialog disappears but nothing happens anymore and I see the following line in the logcat output:
W/InputManagerService( 570): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@436c6bf8
After that I can go 'BACK' to my MenuActivity, but that one is not responding either. And pretty fast a 'Force Close' is shown.
I though I had to do with my initial Activity -> View -> Thread setup and made a modified version based on your maxFPS Activity->View->Thread code as a start. The issue remains.
Below the output of logcat, I added log entries with the names of the functions as soon as they are started. This way you can see the 'flow'.
====> My MenuActivity is currently active
====> I press 'start game'to start the GameActivity
I/ActivityManager( 570): Starting activity: Intent { comp={my.android/my.android.game.GameActivity} }
D/GameActivity( 1503): onCreate();
D/GameView( 1503): init();
D/GameEngine( 1503): init();
D/GameEngine( 1503): fillBitmapCache();
D/GameEngine( 1503): createInputObjectPool();
D/GameActivity( 1503): onStart();
D/GameActivity( 1503): startGame();
D/GameView( 1503): getThread();
D/GameView( 1503): create new Thread;
D/GameThread( 1503): -- CONSTRUCTOR --
D/GameView( 1503): updateThreadSurfaceState();
D/GameThread( 1503): setRunning(true);
D/GameThread( 1503): run();
D/GameActivity( 1503): onResume();
D/GameActivity( 1503): onWindowFocusChanged();
D/GameView( 1503): onWindowFOcusChanged();
D/GameThread( 1503): setPaused(false);
D/GameView( 1503): surfaceCreated();
D/GameView( 1503): updateThreadSurfaceState();
D/GameView( 1503): surfaceChanged();
D/GameThread( 1503): -- LOOP --
D/GameEngine( 1503): processInput();
D/GameEngine( 1503): update();
D/GameEngine( 1503): draw();
I/ActivityManager( 570): Displayed activity my.android/.game.GameActivity: 1023 ms
D/GameActivity( 1503): onWindowFocusChanged();
D/GameView( 1503): onWindowFOcusChanged();
D/GameThread( 1503): setPaused(true);
====> Over here an AlertDialog is shown with a positive & negative button
====> I click the positive button
D/GameActivity( 1503): onWindowFocusChanged();
D/GameView( 1503): onWindowFOcusChanged();
D/GameThread( 1503): setPaused(false);
W/InputManagerService( 570): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@436f6a08
====> I click the back button because AlertDialog disappered and that's it
====> I go back to the previous activity, but no responses and pretty fast I
====> have to choose a 'Force close' to terminate the application completely
W/KeyCharacterMap( 1503): No keyboard for id 0
W/KeyCharacterMap( 1503): Using default keymap: /system/usr/keychars/qwerty.kcm.
bin
D/GameEngine( 1503): onKeyDown();
D/GameThread( 1503): setRunning(false);
D/GameActivity( 1503): onPause();
D/GameActivity( 1503): onWindowFocusChanged();
D/GameView( 1503): onWindowFOcusChanged();
D/GameThread( 1503): setPaused(true);
D/GameView( 1503): surfaceDestroyed();
D/GameView( 1503): updateThreadSurfaceState();
D/GameView( 1503): stopThread();
D/GameView( 1503): Stopping Thread
D/GameThread( 1503): setRunning(false);
W/ActivityManager( 570): Launch timeout has expired, giving up wake lock!
W/ActivityManager( 570): Activity idle timeout for HistoryRecord{4362ce18 {my.android/my.android.menu.MenuActivity}}
W/ActivityManager( 570): Activity destroy timeout for HistoryRecord{43640820 {my.android/my.android.game.GameActivity}}
====> No I'm back in my previous activity which does not repond on keys / touches
====> After 20 seconds a 'Force Close'has to be selected
W/WindowManager( 570): Key dispatching timed out sending to my.android/my.android.menu.MenuActivity
W/WindowManager( 570): Dispatch state: {{KeyEvent{action=1 code=4 repeat=0 meta=0 scancode=158 mFlags=8} to Window{43611e78 my.android/my.android.menu.MenuActivity paused=false} @ 1262717403783 lw=Window{43611e78 my.android/my.android.menu.MenuActivity paused=false} lb=android.os.BinderProxy@436122b8 fin=false gfw=true ed=true tts=0 wf=false fp=false mcf=Window{43611e78 my.android/my.android.menu.MenuActivity paused=false}}}
W/WindowManager( 570): Current state: {{null to Window{43611e78 my.android/my.android.menu.MenuActivity paused=false} @ 1262717469025 lw=Window{43611e78 my.android/my.android.menu.MenuActivity paused=false} lb=android.os.BinderProxy@436122b8 fin=false gfw=true ed=true tts=0 wf=false fp=false mcf=Window{43611e78 my.android/my.android.menu.MenuActivity paused=false}}}
I/ActivityManager( 570): ANR (application not responding) in process: my.android
I/ActivityManager( 570): Annotation: keyDispatchingTimedOut
I/ActivityManager( 570): CPU usage:
I/ActivityManager( 570): Load: 0.01 / 0.07 / 0.08
I/ActivityManager( 570): CPU usage from 9131ms to 76ms ago:
I/ActivityManager( 570): system_server: 7% = 5% user + 2% kernel
I/ActivityManager( 570): qemud: 3% = 0% user + 3% kernel
I/ActivityManager( 570): com.android.phone: 0% = 0% user + 0% kernel
I/ActivityManager( 570): events/0: 0% = 0% user + 0% kernel
I/ActivityManager( 570): adbd: 0% = 0% user + 0% kernel
I/ActivityManager( 570): android.process.acore: 0% = 0% user + 0% kernel
I/ActivityManager( 570): TOTAL: 8% = 4% user + 3% kernel + 0% softirq
I/ActivityManager( 570): Removing old ANR trace file from /data/anr/traces.txt
I/Process ( 570): Sending signal. PID: 1503 SIG: 3
I/dalvikvm( 1503): threadid=7: reacting to signal 3
I/Process ( 570): Sending signal. PID: 612 SIG: 3
I/dalvikvm( 612): threadid=7: reacting to signal 3
I/dalvikvm( 612): Wrote stack trace to '/data/anr/traces.txt'
I/Process ( 570): Sending signal. PID: 715 SIG: 3
I/dalvikvm( 715): threadid=7: reacting to signal 3
I/Process ( 570): Sending signal. PID: 640 SIG: 3
I/dalvikvm( 640): threadid=7: reacting to signal 3
I/Process ( 570): Sending signal. PID: 668 SIG: 3
I/dalvikvm( 668): threadid=7: reacting to signal 3
I/Process ( 570): Sending signal. PID: 570 SIG: 3
I/dalvikvm( 570): threadid=7: reacting to signal 3
I/dalvikvm( 640): Wrote stack trace to '/data/anr/traces.txt'
I/dalvikvm( 715): Wrote stack trace to '/data/anr/traces.txt'
I/dalvikvm( 570): Wrote stack trace to '/data/anr/traces.txt'
I/Process ( 570): Sending signal. PID: 610 SIG: 3
I/dalvikvm( 610): threadid=7: reacting to signal 3
I/dalvikvm( 668): Wrote stack trace to '/data/anr/traces.txt'
I/dalvikvm( 610): Wrote stack trace to '/data/anr/traces.txt'
W/WindowManager( 570): No window to dispatch pointer action 1
I/dalvikvm( 1503): Wrote stack trace to '/data/anr/traces.txt'
W/WindowManager( 570): No window to dispatch pointer action 1
W/WindowManager( 570): No window to dispatch pointer action 0
W/WindowManager( 570): No window to dispatch pointer action 1
W/WindowManager( 570): No window to dispatch pointer action 0
W/WindowManager( 570): No window to dispatch pointer action 1
W/WindowManager( 570): No window to dispatch pointer action 0
W/WindowManager( 570): No window to dispatch pointer action 1
====> Select 'Force Close'
I/ActivityManager( 570): Killing process my.android (pid=1503) at user's request
I/Process ( 570): Sending signal. PID: 1503 SIG: 9
I/WindowManager( 570): WIN DEATH: Window{436b4930 SurfaceView paused=false}
I/WindowManager( 570): WIN DEATH: Window{43652728 my.android/my.android.game.GameActivity paused=false}
I/WindowManager( 570): WIN DEATH: Window{43611e78 my.android/my.android.menu.MenuActivity paused=false}
I/ActivityManager( 570): Process my.android (pid 1503) has died.
W/InputManagerService( 570): Got RemoteException sending setActive(false) notification to pid 1503 uid 10019
I hope you can point me in a direction for fixing this. The last four days I have been looking for clues about a possible workaround / cause. Maybe I'm even using the wrong approach for such a dialog box.
(Sorry for the long post I tried to give you as much detail as possible without just listing all code and asking for a fix.)
I like to put the game activity in charge of this. You can do that in a variety of ways but one easy way is to register your activity with your thread as the handler of a dialog trigger. Then the game thread just calls DialogHandler.showDialog or however you design it.
Of course, that will still be running on your game thread so you'll need to bridge the execution over to the UI thread. There are two ways: You can use an Android.os.Handler or you can put the code into a Runnable and call Context.runOnUiThread(Runnable)
I'm not sure about your force close. Perhaps you have some code blocking the UI thread?
I used the runOnUiThread method to run it via the GameActivity (and this way I could nicely use onCreateDialog / showDialog) and it works as expected.
Thanks, that was exactly what I'm looking for (without knowing ;)!!