如何暂停和恢复surfaceView线程
我有一个surfaceView设置和运行,但是当我恢复它时,我得到一个线程已经启动的错误。什么是应用程序进入后台然后回到前台的正确方法?我修了一下,并设法让应用程序回来而不会崩溃...但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;
}
简单的解决方案是简单地杀死并重启线程。在SurfaceView类中创建方法resume() - 创建线程对象并启动线程对象并暂停() - 杀死线程(请参阅Lunarlander示例)并从surfaceCreated和surfaceDestroyed调用它们以启动和停止线程。
现在在运行SurfaceView的Activity中,还需要从Activity(或片段)onResume()和onPause()调用SurfaceView中的resume()和pause()方法。这不是一个优雅的解决方案,但它会起作用。
您应使用活动的onPause()和的onResume()方法。
首先,在surfaceCreated()中启动线程。此外,在onResume()中,确保线程尚未启动(在线程内部保留一个变量)。如果它没有运行,请将其设置为再次运行。在onPause()中,暂停该线程。在surfaceDestroyed中,再次暂停该线程。
我有它正确设置在适当的地方使用setRunning,但尽管有thread.setRunning(真)在我的onResume我surfaceView为空时,其背在最前沿。线程仍然存在,当我进入主屏幕时它不会崩溃应用程序,并且如果我确实尝试了另一个线程。start(),我会看到线程已启动的错误。有任何想法吗? – jfisk 2010-08-20 18:35:24
您只能启动一次线程。我不知道你的setRunning方法在内部做了什么,但是在Android上正确停止线程的唯一方法是让它从run()方法返回。从那时起,你必须创建一个新的线程对象。你不能再次使用该线程。如果你想'暂停'线程,你必须使用wait()和notifyAll()。谷歌周围例如和正确的理解。 – Moncader 2010-08-21 01:15:07
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...
}
}
}
我正在学习surfaceview,但不能理解你为什么不在while循环中使用break stamenet。我的程序在onResume()期间冻结了,但是在我放置了break之后,它开始了agin,显然创建了一个新的线程。这是我的代码和问题:http://*.com/questions/19200972/android-surfaceview-cant-resume-activity-from-pause – Luther 2013-10-05 21:17:39
阅读Thread.join(),那么你会明白。 – 2013-10-08 02:52:21
活动'onPause'不会总是**自己调用'surfaceDestroyed'。所以这一点就不能解决问题。看到这个问题http://*.com/q/11495842/1180117 – Kiran 2015-03-10 09:42:09
这个好已知的问题的另一个解决方案。可悲的是,我不明白它为什么有效 - 它意外地出现了。但它适用于我,并且很容易实现:不需要重写Activity
的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) {
}
}
}
两个代码块不完整编写的,单纯的概念哪些命令需要哪些方法。另请注意,每次返回应用程序都会调用surfaceChanged()
。
对不起,这种空间消耗的答案。我希望它能正常工作,并会有所帮助。
活动'onPause'不会总是**自己调用'surfaceDestroyed'。所以这不会解决问题。看到这个问题http://*.com/q/11495842/1180117 – Kiran 2015-03-10 09:37:30
试图评论上面接受的答案,但不能,新的这一点。我不认为你应该从SurfaceView和Activity中调用你的开始/停止线程方法。这将导致双重启动/停止线程,并且不能多次启动线程。只需从Activity的onPause和onResume中调用您的方法即可。他们在退出并重新进入应用程序时被调用,以确保您的状态得到正确处理。 SurfaceDestroyed并不总是被调用,这让我困惑了一会儿。
如果使用此方法,请确保在处理画布之前检查运行代码中的有效表面,因为活动将在表面可用之前启动onResume中的线程。
while (_run) {
if (_surfaceHolder.getSurface().isValid()) {
...
}
} //end _run
收回的评论 – tjb 2011-10-17 08:51:30
我已经发现,最好的办法是重写活动控制表面视图,以便用它的方法重新实例化SurfaceView的方法的onResume,然后用的setContentView设置它。这种方法的问题是您需要重新加载SurfaceView正在处理的任何状态。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyCustomSurfaceView(this));
}
@Override
protected void onResume() {
super.onResume();
setContentView(new MyCustomSurfaceView(this));
}
这对我来说伎俩。当我在onResume之前尝试它时,它不起作用。 – sivi 2014-03-13 19:27:28
这是我用过的。该应用程序现在不崩溃。
视图类:
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){}
}
}
我希望这将有助于。
活动'onPause'不会总是**自己调用'surfaceDestroyed'。所以这不会解决问题。看到这个问题http://*.com/q/11495842/1180117 – Kiran 2015-03-10 09:38:58
此错误似乎与月球着陆器错误有关,这个错误非常有名(对Google进行搜索)。毕竟这一次,以及几个Android版本发布后,该错误依然存在,并且没有人打扰更新它。我发现这个用最少的代码杂乱的工作:
public void surfaceCreated(SurfaceHolder holder) {
if (thread.getState==Thread.State.TERMINATED) {
thread = new MainThread(getHolder(),this);
}
thread.setRunning(true);
thread.start();
}
活动'onPause'不会总是**自己调用'surfaceDestroyed'。所以这只会解决问题。看到这个问题http://*.com/q/11495842/1180117 – Kiran 2015-03-10 09:43:19
我爱Ur的想法,我一直在努力寻找一些容易。因为“surfaceDestroyed”不是每次都调用,而是“onPause”。就像按下“电源”按钮然后返回。所以我认为你的选择是一个非常好的选择。 – 2010-10-30 02:34:49