SurfaceView Сбой при возврате из другого действия - PullRequest
0 голосов
/ 07 ноября 2011

У меня проблема с потоком в 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"/>
    ...

а мой фоновый класс - это типичный класс поверхности, с держателем, потоком, который вызовет наш метод onDraw и т. д. Некоторый код, чтобы избежать вопросов (init () вызывается в методах конструктора):

    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();
}

и поток strop / resume в классе surfaceview:

    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) {}
    }
}

1 Ответ

0 голосов
/ 07 ноября 2011

IIRC-поверхность готова к манипуляциям только после обратного вызова surfaceChanged (), а не SurfaceCreated (), а SurfaceChanged () вызывается после onResume () - переместить туда инициализацию и запуск потока (в surfaceChanged ())

...