本文介绍了结束SurfaceView和GameThread在退出应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个surfaceview和gameThread类。
该gameThread不断更新和绘画上SurfaceView类。

现在,当我退出程序(由pressing家庭或后退按钮),我得到一个消息,应用力封闭。这是因为GameThread仍然尝试画上删除surfaceview ...

那么,如何正确结束应用程序没有得到这个强制关闭通知?我想GameThread类时停止后退按钮是pssed $ P $。它应该停留在家庭和在后台运行pressing时。当再次进入仍在运行游戏就应该恢复....

任何想法?

这是我的GameThread类:

 公共类GameThread继承Thread {私人GameView图。
公共布尔isRunning = FALSE;公共GameThread(GameView视图){
    this.view =视图。
}公共无效setRunning(布尔setRunning){
    isRunning = setRunning;
}公共无效的run(){
    而(isRunning){
        帆布C = NULL;
        view.update();
        尝试{
            C = view.getHolder()lockCanvas()。
            同步(view.getHolder()){
                view.draw(C);
            }
        } {最后
            如果(C!= NULL){
                view.getHolder()unlockCanvasAndPost(c)中;
            }
        }
    }
}

它不断更新我的GameView类:

公共类GameView扩展SurfaceView {

 私人GameThread gameThread;公共GameView(上下文的背景下,活动活动){
    超级(上下文);
    gameThread =新GameThread(本);
    在里面();
    支架= getHolder();
    holder.addCallback(新SurfaceHolder.Callback(){        @覆盖
        公共无效surfaceDestroyed(SurfaceHolder持有人){        }
        @覆盖
        公共无效surfaceCreated(SurfaceHolder持有人){
            gameThread.setRunning(真);
            gameThread.start();        }
        @覆盖
        公共无效surfaceChanged(SurfaceHolder架,INT格式,宽度INT,
                INT高度){
        }
    });
}
公共无效的init(){}公共无效更新(){}公共无效画(油画画布){
    super.draw(画布);}
}

在pressing回家时,我的logcat显示此设置:

  02-24 18:24:59.336:E / SurfaceHolder(839):异常锁定面
02-24 18:24:59.336:E / SurfaceHolder(839):java.lang.IllegalStateException:表面已经被释放。
02-24 18:24:59.336:E / SurfaceHolder(839):在android.view.Surface.checkNotReleasedLocked(Surface.java:437)
02-24 18:24:59.336:E / SurfaceHolder(839):在android.view.Surface.lockCanvas(Surface.java:245)
02-24 18:24:59.336:E / SurfaceHolder(839):在android.view.SurfaceView $ 4.internalLockCanvas(SurfaceView.java:872)

主要活动:

 公共类MainActivity延伸活动{私人的RelativeLayout RelativeLayout的;
私人GameView gameView;@覆盖
保护无效的onCreate(捆绑savedInstanceState){
    super.onCreate(savedInstanceState);
    gameView =新GameView(这一点,这一点);
    的setContentView(R.layout.activity_main);
    的RelativeLayout =(RelativeLayout的)findViewById(R.id.mainView);
    relativeLayout.addView(gameView);
}@覆盖
公共无效onBack pressed(){
    // TODO自动生成方法存根
    super.onBack pressed();
    gameView.onBack pressed();
}@覆盖
公共布尔onCreateOptionsMenu(菜单菜单){
    //充气菜单;如果是present这增加了项目操作栏。
    。getMenuInflater()膨胀(R.menu.main,菜单);
    返回true;
}}


解决方案

表面背后的 SurfaceView 被破坏之间的的onPause()的onDestroy()在应用程序生命周期。在的onPause发送邮件到您的渲染线程(),并等待线程关闭。

有关的示例,请参阅中的硬件缩放锻炼活动。它开始在渲染线程中的 surfaceCreated()回调。

SurfaceHolder

更新:感觉怪异启动螺纹surfaceCreated()的onPause停止它(),打完有点洗牌HardwareScalerActivity现在停止线程 surfaceDestroyed()。 (该SurfaceView文档是一个有点暧昧 - 它说,表面上是有效的之间surfaceCreated() surfaceDestroyed() - 但是看着这似乎是在预期使用的SurfaceView实现)

更新2:我发现它没有处理好案件后更新了code更多一些。现在有一个60行megacomment的来源,这也可以被看作在my回答类似的问题。

更新3:的巨型评论变成了一个的。 Grafika的硬件缩放锻炼活动演示方式#2,而从相机质感演示方法1。

I've got a surfaceview and a gameThread class.The gameThread keeps updating and painting on the SurfaceView class.

Now when I exit the app (By pressing the home or back button) I get a message that the app force closed. That's because the GameThread still tries to draw on the erased surfaceview...

So how do i properly end the app without getting this force close notification? I would like the GameThread class to stop when the back button is pressed. It should pause when pressing on home and running in the background. When re-entering the still running game it should resume....

Any ideas?

This is my GameThread class:

public class GameThread extends Thread{

private GameView view;
public boolean isRunning = false;

public GameThread(GameView view) {
    this.view = view;
}

public void setRunning(boolean setRunning) {
    isRunning = setRunning;
}

public void run() {
    while(isRunning) {
        Canvas c = null;
        view.update();
        try {
            c = view.getHolder().lockCanvas();
            synchronized (view.getHolder()) {
                view.draw(c);
            }
        }finally {
            if(c != null) {
                view.getHolder().unlockCanvasAndPost(c);
            }
        }
    }
}

It keeps updating my GameView class:

public class GameView extends SurfaceView{

private GameThread gameThread;

public GameView(Context context, Activity activity) {
    super(context);
    gameThread = new GameThread(this);
    init();
    holder = getHolder();
    holder.addCallback(new SurfaceHolder.Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

        }
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            gameThread.setRunning(true);
            gameThread.start();

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


public void init() {

}

public void update() {

}

public void draw(Canvas canvas) {
    super.draw(canvas);

}
}

When pressing home my logcat shows this up:

02-24 18:24:59.336: E/SurfaceHolder(839): Exception locking surface
02-24 18:24:59.336: E/SurfaceHolder(839): java.lang.IllegalStateException: Surface has already been released.
02-24 18:24:59.336: E/SurfaceHolder(839):   at android.view.Surface.checkNotReleasedLocked(Surface.java:437)
02-24 18:24:59.336: E/SurfaceHolder(839):   at android.view.Surface.lockCanvas(Surface.java:245)
02-24 18:24:59.336: E/SurfaceHolder(839):   at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:872)

Main activity:

public class MainActivity extends Activity {

private RelativeLayout relativeLayout;
private GameView gameView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    gameView = new GameView(this, this);
    setContentView(R.layout.activity_main);
    relativeLayout = (RelativeLayout)findViewById(R.id.mainView);
    relativeLayout.addView(gameView);
}

@Override
public void onBackPressed() {
    // TODO Auto-generated method stub
    super.onBackPressed();
    gameView.onBackPressed();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

}
解决方案

The Surface underlying the SurfaceView gets destroyed between onPause() and onDestroy() in the app lifecycle. Send a message to your renderer thread in onPause(), and wait for the thread to shut down.

For an example, see the "Hardware scaler exerciser" activity in Grafika. It starts the render thread in the SurfaceHolder's surfaceCreated() callback.

Update: it felt weird to start the thread in surfaceCreated() and stop it in onPause(), so after a bit of reshuffling HardwareScalerActivity now stops the thread in surfaceDestroyed(). (The SurfaceView documentation is a bit ambiguous -- it says the Surface is valid "between surfaceCreated() and surfaceDestroyed()" -- but looking at the SurfaceView implementation this appears to be the expected usage.)

Update 2: I updated the code some more after finding cases it didn't handle well. There's now a 60-line megacomment in the sources, which can also been seen in my answer to a similar question.

Update 3: The mega-comment turned into an architecture doc appendix. Grafika's "hardware scaler exerciser" activity demonstrates approach #2, while "texture from camera" demonstrates approach #1.

这篇关于结束SurfaceView和GameThread在退出应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-26 20:50