我有一个surfaceView设置并运行,但是当我恢复它时,我收到一个错误,该线程已经启动。当应用程序进入后台然后返回前台时,处理的正确方法是什么?我已经修好了并且设法让应用程序无法崩溃而返回......但是SurfaceView不再绘制任何东西了。我的代码:
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e("sys","surfaceCreated was called.");
if(systemState==BACKGROUND){
thread.setRunning(true);
}
else {
thread.setRunning(true);
thread.start();
Log.e("sys","started thread");
systemState=READY;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e("sys","surfaceDestroyed was called.");
thread.setRunning(false);
systemState=BACKGROUND;
}
答案 0 :(得分:11)
简单的解决方案是简单地杀死并重新启动线程。创建方法resume() - 创建线程对象并启动它 - 并暂停() - 杀死线程(参见Lunarlander示例) - 在SurfaceView类中,从surfaceCreated和surfaceDestroyed中调用它们来启动和停止线程。
现在在运行SurfaceView的Activity中,您还需要从Activity(或片段)onResume()和onPause()调用SurfaceView中的resume()和pause()方法。这不是一个优雅的解决方案,但它会起作用。
答案 1 :(得分:4)
此错误似乎与月球着陆器错误有关,这个错误非常有名(在Google上进行搜索)。经过所有这段时间,并在几个Android版本发布后,该bug仍然存在 没人打扰更新它。我发现这可以解决最少的代码混乱:
public void surfaceCreated(SurfaceHolder holder) {
if (thread.getState==Thread.State.TERMINATED) {
thread = new MainThread(getHolder(),this);
}
thread.setRunning(true);
thread.start();
}
答案 2 :(得分:2)
public void surfaceCreated(SurfaceHolder holder) {
if (!_thread.isAlive()) {
_thread = new MyThread(this, contxt);
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
答案 3 :(得分:2)
我发现的最好方法是覆盖控制表面视图的活动的onResume方法,以便使用该方法重新实例化SurfaceView,然后使用setContentView设置它。这种方法的问题是你需要重新加载SurfaceView正在处理的任何状态。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyCustomSurfaceView(this));
}
@Override
protected void onResume() {
super.onResume();
setContentView(new MyCustomSurfaceView(this));
}
答案 4 :(得分:1)
试图对上面接受的答案发表评论,但不能,对此不熟悉。我不认为你应该从SurfaceView和Activity调用你的启动/停止线程方法。这将导致双重启动/停止线程,并且您不能多次启动线程。只需从Activity的onPause和onResume中调用您的方法即可。退出并重新进入应用程序时会调用它们,这样可以确保您的状态得到妥善处理。 surfaceDestroyed并不总是被调用,这让我搞砸了一段时间。
如果使用此方法,请确保在使用画布之前检查运行代码中的有效曲面,因为Activity将在曲面可用之前在onResume中启动线程。
while (_run) {
if (_surfaceHolder.getSurface().isValid()) {
...
}
} //end _run
答案 5 :(得分:1)
这就是我用过的东西。该应用程序现在不会崩溃。
查看课程:
holder.addCallback(new Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
gameLoopThread.setRunning(false);
gameLoopThread.stop();
}
public void surfaceCreated(SurfaceHolder holder) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
在GameLoopThread中:
private boolean running = false;
public void setRunning(boolean run) {
running = run;
}
@Override
public void run() {
long ticksPs=1000/FPS;
long startTime;
long sleepTime;
while(running){
Canvas c = null;
startTime=System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime=ticksPs-(System.currentTimeMillis()-startTime);
try{
if(sleepTime>0){
sleep(sleepTime);
}
else
sleep(10);
} catch(Exception e){}
}
}
我希望它会有所帮助。
答案 6 :(得分:0)
您应该使用Activities onPause()和onResume()方法。
首先,在surfaceCreated()中,启动线程。另外,在onResume()中,确保线程尚未启动(在线程内部保留一个变量或其他内容)。然后,如果它没有运行,请将其再次设置为运行。在onPause()中,暂停线程。在surfaceDestroyed中,再次暂停线程。
答案 7 :(得分:0)
这个众所周知的问题的另一个解决方案。可悲的是,我不明白它为什么会起作用 - 它意外地出现了。但它对我有用并且易于实现:不会覆盖Activity
的{{1}},onPause()
,onResume()
,onStart()
,也不会写出特殊的内容线程方法(如onStop()
,resume()
)是必需的。
特殊要求是将所有变化的变量放在除渲染线程类之外的其他变量中。
要添加到渲染线程类的要点:
pause()
现在,有关class RefresherThread extends Thread {
static SurfaceHolder threadSurfaceHolder;
static YourAppViewClass threadView;
static boolean running;
public void run (){
while(running){
//your amazing draw/logic cycle goes here
}
}
}
的重要事项:
YourAppViewClass
上面的两个代码块不是完整编写的类,而仅仅是需要哪些方法的命令的概念。另请注意,每次返回应用都会调用class YourAppViewClass extends SurfaceView implements SurfaceHolder.Callback {
static RefresherThread surfaceThread;
public YourAppViewClass(Activity inpParentActivity) {
getHolder().addCallback(this);
RefresherThread.threadSurfaceHolder = getHolder();
RefresherThread.threadView = this;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
surfaceThread = new RefresherThread();
surfaceThread.running=true;
surfaceThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceThread.running=false;
try {
surfaceThread.join();
} catch (InterruptedException e) {
}
}
}
。
很抱歉这样费用太高的答案。我希望它能正常运作并有所帮助。