I have a really simple android app that just displays a blank white screen. When I close the app by pressing the HOME button, then try to open the app again, it crashes and I get the "Force Close" button. In Eclipse I'm getting this error, "ActivityManager: Warning: Activity not started because the current activity is being kept for the user.". How do I fix this crash?
public class HelloAndroid extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new Panel(this));
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private TutorialThread _thread;
public Panel(Context context) {
super(context);
// register our interest in hearing about changes to our surface
SurfaceHolder holder = getHolder();
holder.addCallback(this);
_thread = new TutorialThread(holder, this);
setFocusable(true);
}
@Override
public void onDraw(Canvas canvas) {
// Clear the background
canvas.drawColor(Color.WHITE);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// resize canvas here
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
_thread.setRunning(true);
_thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
@Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
Adding the LogCat
03-15 15:36:05.579: INFO/AndroidRuntime(4441): NOTE: attach of thread 'Binder Thread #2' failed
03-15 15:36:05.719: DEBUG/AndroidRuntime(4449): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
03-15 15:36:05.719: DEBUG/AndroidRuntime(4449): CheckJNI is OFF
03-15 15:36:05.719: DEBUG/dalvikvm(4449): creating instr width table
03-15 15:36:05.759: DEBUG/AndroidRuntime(4449): --- registering native functions ---
03-15 15:36:05.969: INFO/ActivityManager(1294): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.helloandroid/.HelloAndroid }
03-15 15:36:05.979: DEBUG/Launcher(1371): onPause+
03-15 15:36:05.979: DEBUG/Launcher.DragController(1371): +endDrag: false
03-15 15:36:05.979: DEBUG/Launcher.DragController(1371): mDragging == false
03-15 15:36:05.979: DEBUG/Launcher.DragController(1371): -endDrag: false
03-15 15:36:05.979: DEBUG/Launcher(1371): onPause-
03-15 15:36:05.999: DEBUG/AndroidRuntime(4428): Shutting down VM
03-15 15:36:05.999: DEBUG/AndroidRuntime(4449): Shutting down VM
03-15 15:36:05.999: WARN/dalvikvm(4428): threadid=1: thread exiting with uncaught exception (group=0x4001d7e0)
03-15 15:36:06.009: DEBUG/dalvikvm(4449): Debugger has detached; object registry had 1 entries
03-15 15:36:06.009: INFO/AndroidRuntime(4449): NOTE: attach of thread 'Binder Thread #3' failed
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): FATAL EXCEPTION: main
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): java.lang.IllegalThreadStateException: Thread already started.
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at java.lang.Thread.start(Thread.java:1322)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at com.example.helloandroid.HelloAndroid$Panel.surfaceCreated(HelloAndroid.java:55)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.view.SurfaceView.updateWindow(SurfaceView.java:538)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:206)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.view.View.dispatchWindowVisibilityChanged(View.java:3888)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:725)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:725)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.view.ViewRoot.performTraversals(ViewRoot.java:748)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.view.ViewRoot.handleMessage(ViewRoot.java:1737)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.os.Handler.dispatchMessage(Handler.java:99)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.os.Looper.loop(Looper.java:123)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at android.app.ActivityThread.main(ActivityThread.java:4627)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at java.lang.reflect.Method.invokeNative(Native Method)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at java.lang.reflect.Method.invoke(Method.java:521)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
03-15 15:36:06.029: ERROR/AndroidRuntime(4428): at dalvik.system.NativeStart.main(Native Method)
03-15 15:36:06.039: WARN/ActivityManager(1294): Force finishing activity com.example.helloandroid/.HelloAndroid
03-15 15:36:06.541: WARN/ActivityManager(1294): Activity pause timeout for HistoryRecord{450300c0 com.example.helloandroid/.HelloAndroid}
03-15 15:36:06.549: DEBUG/Launcher(1371): onResume+
03-15 15:36:06.549: DEBUG/Launcher.DragController(1371): +endDrag: false
03-15 15:36:06.549: DEBUG/Launcher.DragController(1371): mDragging == false
03-15 15:36:06.549: DEBUG/Launcher.DragController(1371): -endDrag: false
03-15 15:36:06.549: DEBUG/Launcher(1371): onResume-
03-15 15:36:08.645: ERROR/KINETO(1370): KLOG0C3- xmk_QueryOSQueue SDL Queue empty : WAIT_FOREVER
Apps on Android can crash because of low storage space, too many apps running simultaneously, a weak internet connection, or not having the proper app updates installed.
Improper App installation can cause Android Apps to crash. You must download the App from the Google Play Store and only use it once it is successfully and completely installed on your device. If your Apps stops abruptly, delete, or uninstall the App from your device and reinstall it after a few minutes.
Select an app. On the left menu, select Quality > Android vitals > Crashes and ANRs. Near the center of your screen, use the filters to help you find and diagnose issues. Alternatively, select a cluster to get more details about a specific crash or ANR error.
I've answered a question like this here.
The error you're getting is probably caused by your Thread
(without seeing the full Logcat it's hard to tell though). You're starting it every time the surface is created, which will make your application crash because you can't call Thread.start()
twice. Look at my link above for a more in-depth description of the problem and how you should solve it.
Since my explanation wasn't enough I will post the whole solution:
Inside your Runnable/Thread
:
private Object mPauseLock = new Object();
private boolean mPaused;
// Constructor stuff.
// This should be after your drawing/update code inside your thread's run() code.
synchronized (mPauseLock) {
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
}
}
}
// Two methods for your Runnable/Thread class to manage the thread properly.
public void onPause() {
synchronized (mPauseLock) {
mPaused = true;
}
}
public void onResume() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
In your SurfaceView
class:
private boolean mGameIsRunning;
@Override
public void surfaceCreated(SurfaceHolder holder) {
// Your own start method.
start();
}
public void start() {
if (!mGameIsRunning) {
thread.start();
mGameIsRunning = true;
} else {
thread.onResume();
}
}
The solution below was tested. The code checks thread state, and if terminated creates a new one. No crashes, the only problem I can see is the game state is not saved so basically getting back from a HOME key press, starts the game again. p.s. remember to pass through the context from Lunarview view and set to mContextLunarView. Hope this helps. These forums are awesome. Keep it up.
public void surfaceCreated(SurfaceHolder holder) {
// start the thread here so that we don't busy-wait in run()
// waiting for the surface to be created
if(thread.getState() == Thread.State.TERMINATED) {
//LunarView Thread state TERMINATED..make new...under CheckCreateThread
thread = new LunarThread(holder, mContextLunarView, new Handler() {
@Override
public void handleMessage(Message m) {
mStatusText.setVisibility(m.getData().getInt("viz"));
mStatusText.setText(m.getData().getString("text"));
}
});
}
thread.setRunning(true);
thread.start();
}
Here is a simple solution which may be acceptable in some cases, like a background animation screen and activities which states do not need to be restored - the surface view activity needs to finish on pause.
protected void onPause() {
super.onPause();
finish();
}
The better solution is to move the creation of the thread from the constructor into on surfaceCretaed like this:
@Override
public void surfaceCreated(SurfaceHolder holder) {
_thread = new TutorialThread(holder, this);
_thread.setRunning(true);
_thread.start();
}
Then in the thread loop create a pause flag:
if(!pause){
_panel.onDraw(c);
}
finally in onPause and onRestore for the activity set the pause flag:
protected void onResume() {
super.onResume();
pause = false;
}
protected void onPause() {
super.onPause();
pause = true;
}
When the user clicks Home button surfaceDestroyed is invoked which will shut down the current thread "_thread". When he returns to the app, surfaceCreated will assign the reference "_thread" to a new thread, while the old thread object will be removed by the garbage collector.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With