【问题标题】:Android app not responding when closedAndroid应用程序关闭时没有响应
【发布时间】:2013-03-01 18:42:06
【问题描述】:

我正在开发一款适用于 android 的游戏,当我关闭应用程序时它崩溃了。我认为这是因为我正在使用空画布进行渲染。当我进行空检查时,程序不会崩溃,但在关闭后不会重新打开。这是我的线程的运行:

public void run() {
    Canvas canvas;
    Log.d(TAG, "Starting game loop");

    long beginTime;     // the time when the cycle begun
    long timeDiff;      // the time it took for the cycle to execute
    int sleepTime;      // ms to sleep (<0 if we're behind)
    int framesSkipped;  // number of frames being skipped 

    sleepTime = 0;

    while (running) {
        canvas = null;
        // try locking the canvas for exclusive pixel editing
        // in the surface
        try {
            canvas = this.surfaceHolder.lockCanvas();
            synchronized (surfaceHolder) {
                beginTime = System.currentTimeMillis();
                framesSkipped = 0;  // resetting the frames skipped
                // update game state 
                this.gamePanel.update();
                // render state to the screen
                // draws the canvas on the panel
                this.gamePanel.render(canvas);              
                // calculate how long did the cycle take
                timeDiff = System.currentTimeMillis() - beginTime;
                // calculate sleep time
                sleepTime = (int)(FRAME_PERIOD - timeDiff);

                if (sleepTime > 0) {
                    // if sleepTime > 0 we're OK
                    try {
                        // send the thread to sleep for a short period
                        // very useful for battery saving
                        Thread.sleep(sleepTime);    
                    } catch (InterruptedException e) {}
                }

                while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
                    // we need to catch up
                    this.gamePanel.update(); // update without rendering
                    sleepTime += FRAME_PERIOD;  // add frame period to check if in next frame
                    framesSkipped++;
                }
            }
        } finally {
            // in case of an exception the surface is not left in 
            // an inconsistent state
            if (canvas != null) {
                surfaceHolder.unlockCanvasAndPost(canvas);
            }
        }   // end finally
    }
}

这里是表面类中的相关方法。

    @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
}


@Override
public void surfaceCreated(SurfaceHolder holder) {
    // at this point the surface is created and
    // we can safely start the game loop
    thread.setRunning(true);
    thread.start();
}

@Override
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;
    while (retry) {
        try {
            thread.setRunning(false);
            thread.join();
            retry = false;
        } catch (InterruptedException e) {
            // try again shutting down the thread
        }
    }
    Log.d(TAG, "Thread was shut down cleanly");
}

空检查是否正确,我只是缺少恢复活动的方法?

当 nullcheck 没有到位时的 Logcat:

03-01 10:37:19.557: E/AndroidRuntime(25129): FATAL EXCEPTION: Thread-16380
03-01 10:37:19.557: E/AndroidRuntime(25129): java.lang.NullPointerException
03-01 10:37:19.557: E/AndroidRuntime(25129):    at org.awesome.AndroidGame.MainGamePanel.render(MainGamePanel.java:192)
03-01 10:37:19.557: E/AndroidRuntime(25129):    at org.awesome.AndroidGame.MainThread.run(MainThread.java:73)
03-01 10:37:23.357: E/BitmapFactory(25280): Unable to decode stream: java.io.FileNotFoundException: /level_1_1.png: open failed: ENOENT (No such file or directory)
03-01 10:37:36.097: E/AndroidRuntime(25280): FATAL EXCEPTION: Thread-16395
03-01 10:37:36.097: E/AndroidRuntime(25280): java.lang.NullPointerException
03-01 10:37:36.097: E/AndroidRuntime(25280):    at org.awesome.AndroidGame.MainGamePanel.render(MainGamePanel.java:192)
03-01 10:37:36.097: E/AndroidRuntime(25280):    at org.awesome.AndroidGame.MainThread.run(MainThread.java:73)
03-01 11:02:49.227: E/AndroidRuntime(26150): FATAL EXCEPTION: Thread-16425
03-01 11:02:49.227: E/AndroidRuntime(26150): java.lang.NullPointerException
03-01 11:02:49.227: E/AndroidRuntime(26150):    at org.awesome.AndroidGame.MainGamePanel.render(MainGamePanel.java:192)
03-01 11:02:49.227: E/AndroidRuntime(26150):    at org.awesome.AndroidGame.MainThread.run(MainThread.java:73)
03-01 11:02:53.717: E/AndroidRuntime(26177): FATAL EXCEPTION: Thread-16428
03-01 11:02:53.717: E/AndroidRuntime(26177): java.lang.NullPointerException
03-01 11:02:53.717: E/AndroidRuntime(26177):    at org.awesome.AndroidGame.MainGamePanel.render(MainGamePanel.java:192)
03-01 11:02:53.717: E/AndroidRuntime(26177):    at org.awesome.AndroidGame.MainThread.run(MainThread.java:73)

使用 nullcheck 时的 Logcat:

03-01 11:58:50.297: E/AndroidRuntime(32292): FATAL EXCEPTION: main
03-01 11:58:50.297: E/AndroidRuntime(32292): java.lang.IllegalThreadStateException: Thread already started.
03-01 11:58:50.297: E/AndroidRuntime(32292):    at java.lang.Thread.start(Thread.java:1045)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at org.awesome.AndroidGame.MainGamePanel.surfaceCreated(MainGamePanel.java:83)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.SurfaceView.updateWindow(SurfaceView.java:569)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:231)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.View.dispatchWindowVisibilityChanged(View.java:7537)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1039)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1039)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1039)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1211)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.Choreographer.doCallbacks(Choreographer.java:562)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.Choreographer.doFrame(Choreographer.java:532)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.os.Handler.handleCallback(Handler.java:725)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.os.Handler.dispatchMessage(Handler.java:92)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.os.Looper.loop(Looper.java:137)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at android.app.ActivityThread.main(ActivityThread.java:5039)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at java.lang.reflect.Method.invokeNative(Native Method)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at java.lang.reflect.Method.invoke(Method.java:511)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
03-01 11:58:50.297: E/AndroidRuntime(32292):    at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

  • 当您说“关闭应用程序”时,您是指点击返回按钮、点击主页按钮,还是在您的代码中提供了自定义退出功能?
  • 两个按钮都使我的应用程序崩溃,但我专门讨论的是主页按钮。
  • LogCat 的堆栈跟踪是否指向特定的代码行?
  • 是的,线程中的渲染调用
  • 引发了什么异常?你能发布完整的堆栈跟踪吗?

标签: android surfaceview forceclose


【解决方案1】:

在你开始你的话题之前,我相信你应该检查它是否已经存在。

据我了解,您无法在 Android 中重新启动线程,因此您应该检查它以前是否存在,如果存在,请像这样启动一个新线程:

if(thread.getState()==Thread.State.TERMINATED){            //Exists?        
 thread = new Thread(holder, context, handler);}           //Re-Create

thread.setRunning(true);
    thread.start();

至于 null 画布,如果您的意思是在您的 run 方法(主 w'hile 循环)中检查 null,请在解锁和发布之前的“finally”部分中,是的,这是正确的。

但是我感觉你并不是说这张支票。当我按下后退键时,我遇到了类似的问题,由于某种原因,Null Canvas 被间歇性地传递给我的 onDraw/Render 方法。实际上,我必须将该方法中的整个代码封装在针对空画布的检查中,这样它只会在检查返回负数时呈现!它工作并且在那之后非常稳定。

如果我没记错的话,在互联网上进行了大量研究后,似乎这是少数人遇到的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-13
    • 2014-01-31
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 2016-09-15
    • 2016-04-11
    • 1970-01-01
    相关资源
    最近更新 更多