从另一个活动返回时 SurfaceView 崩溃

发布于 12-14 05:54 字数 4648 浏览 3 评论 0原文

我的 SurfaceView 有一个线程问题,这很常见,但我还没有在任何地方找到解决方案。

我在框架布局中使用 SurfaceView 作为背景:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/blobmusic_layout"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.myapp.Background
    android:id="@+id/background_blobmusic"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
    ...

我的背景类是典型的 SurfaceView 类,带有支架,线程将调用我们的 onDraw 方法等。一些代码可以避免出现问题(在构造函数方法):

    public void init() {
    ready = false;
    holder = getHolder();
    holder.addCallback( new Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            boolean retry = true;
            while (retry) {
                try {
                    bgdt.setRunning(false);
                    bgdt.join();
                    retry = false;
                } catch (InterruptedException e) {}
            }
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            holder.setFormat(PixelFormat.RGBA_8888);
            estrelles = new Estrelles(getResources(),getHeight());
            bgdt.setRunning(true);
            bgdt.start();
            ready = true;
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
            // TODO Auto-generated method stub

        }
    });

和我的线程类(bgtd):

public class BGDrawThread extends Thread {
private Background view;
static final long FPS = 60;
private boolean running = false;

public BGDrawThread(Background view) {
      this.view = view;
}

public boolean isRunning() {
    return running;
}

public void setRunning(boolean run) {
      running = run;
}

@Override
public void run() {
    long ticksPS = 1000/FPS;
    long startTime;
    long sleepTime;
    //fps checker
    long contms=0;
    long lasttimecheck = System.currentTimeMillis();
    int fps=0;
    while (running) {
        if(contms>1000) {
            //souts ??
            contms=0;
            fps=0;
            lasttimecheck = System.currentTimeMillis();
        }
        else {
            fps++;
            contms+=System.currentTimeMillis()-lasttimecheck;
            lasttimecheck=System.currentTimeMillis();
        }
        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/onresume 方法的代码类:

    @Override
protected void onResume() {
    super.onResume();
    Background bmbg = (Background) findViewById(R.id.background_blobmusic);
    bmbg.resumethread();
}
@Override
protected void onPause() {
    super.onPause();
    Background bmbg = (Background) findViewById(R.id.background_blobmusic);
    bmbg.stopthread();
}

和SurfaceView 类中的 strop/resume 线程:

    public void stopthread() {
    if(!bgdt.isAlive()) return;
    boolean retry = true;
    while (retry) {
        try {
            bgdt.setRunning(false);
            bgdt.join();
            retry = false;
        } catch (InterruptedException e) {}
    }
}
public void resumethread() {
    if(ready && !bgdt.isRunning()) {
        bgdt.setRunning(true);
        bgdt.start();
    }
}

欢迎所有帮助:)

编辑:我让它运行(可能不是一个优雅的解决方案,但我将代码留在这里): (查看下面的评论以查看其他更改)

public void startthread() {
    if(!surfacecreated) return;
    if(threadrunning) return;
    bgdt = new BGDrawThread(this);
    bgdt.setRunning(true);
    bgdt.start();
    threadrunning = true;
}

public void stopthread() {
    boolean retry = true;
    while (retry) {
        try {
            bgdt.setRunning(false);
            bgdt.join();
            threadrunning = false;
            retry = false;

        } catch (InterruptedException e) {}
    }
}

i have a thread problem with my surfaceView, its quite common but i have not found a solution anywhere.

I use a SurfaceView as a Background in a frame layout:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/blobmusic_layout"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <com.myapp.Background
    android:id="@+id/background_blobmusic"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
    ...

and my background class is the tipical surfaceview class, with the holder, the thread wich will call our onDraw method, etc. Some code to avoid questions (init() is called in the constructor methods):

    public void init() {
    ready = false;
    holder = getHolder();
    holder.addCallback( new Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            boolean retry = true;
            while (retry) {
                try {
                    bgdt.setRunning(false);
                    bgdt.join();
                    retry = false;
                } catch (InterruptedException e) {}
            }
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            holder.setFormat(PixelFormat.RGBA_8888);
            estrelles = new Estrelles(getResources(),getHeight());
            bgdt.setRunning(true);
            bgdt.start();
            ready = true;
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
            // TODO Auto-generated method stub

        }
    });

and my thread class (bgtd):

public class BGDrawThread extends Thread {
private Background view;
static final long FPS = 60;
private boolean running = false;

public BGDrawThread(Background view) {
      this.view = view;
}

public boolean isRunning() {
    return running;
}

public void setRunning(boolean run) {
      running = run;
}

@Override
public void run() {
    long ticksPS = 1000/FPS;
    long startTime;
    long sleepTime;
    //fps checker
    long contms=0;
    long lasttimecheck = System.currentTimeMillis();
    int fps=0;
    while (running) {
        if(contms>1000) {
            //souts ??
            contms=0;
            fps=0;
            lasttimecheck = System.currentTimeMillis();
        }
        else {
            fps++;
            contms+=System.currentTimeMillis()-lasttimecheck;
            lasttimecheck=System.currentTimeMillis();
        }
        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) {}
    }
}
}

This works fine, until another activity comes to front and then we come back from it, that crashes.

Here's my code of onpause/onresume methods of the class:

    @Override
protected void onResume() {
    super.onResume();
    Background bmbg = (Background) findViewById(R.id.background_blobmusic);
    bmbg.resumethread();
}
@Override
protected void onPause() {
    super.onPause();
    Background bmbg = (Background) findViewById(R.id.background_blobmusic);
    bmbg.stopthread();
}

and the strop/resume thread in the surfaceview class:

    public void stopthread() {
    if(!bgdt.isAlive()) return;
    boolean retry = true;
    while (retry) {
        try {
            bgdt.setRunning(false);
            bgdt.join();
            retry = false;
        } catch (InterruptedException e) {}
    }
}
public void resumethread() {
    if(ready && !bgdt.isRunning()) {
        bgdt.setRunning(true);
        bgdt.start();
    }
}

All help is welcome :)

EDIT: i made it run (probably not an elegant solution, but i leave the code here):
(look at the comment below to see the other changes)

public void startthread() {
    if(!surfacecreated) return;
    if(threadrunning) return;
    bgdt = new BGDrawThread(this);
    bgdt.setRunning(true);
    bgdt.start();
    threadrunning = true;
}

public void stopthread() {
    boolean retry = true;
    while (retry) {
        try {
            bgdt.setRunning(false);
            bgdt.join();
            threadrunning = false;
            retry = false;

        } catch (InterruptedException e) {}
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

素手挽清风2024-12-21 05:54:42

IIRC 表面仅在 surfaceChanged() 回调之后才准备好进行操作,而不是 surfaceCreated() ,并且在 onResume() 之后调用 surfaceChanged() - 将初始化和线程启动移动到那里(到 surfaceChanged() )

IIRC surface is ready for manipulations only after surfaceChanged() callback, not surfaceCreated() , and surfaceChanged() is called after onResume() - move your initialisation and thread startup there ( to surfaceChanged() )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文