Android SurfaceView не создается в портретном режиме - PullRequest
2 голосов
/ 05 января 2012

У меня есть простой LinearLayout с пользовательским классом SurfaceView и некоторыми кнопками. Ранее я указывал ориентацию на Пейзаж в теге «Активность» в манифесте, однако теперь мне нужно сделать его портретным. По какой-то причине, когда я заставляю портрет ориентации, SurfaceView не создается. Я протестировал макет, просто используя один FrameLayout и внутри этого единственного экземпляра моего класса SurfaceView, но, тем не менее, он не будет создан должным образом.

Ошибка, которую я получаю, зависит от того, каким является первый экземпляр Thread в SurfaceView. Обычно это мой пользовательский интерфейс в onCreate, запрашивающий дескриптор потока, который вызывает исключение NullPointerException.

Есть идеи, почему мой код работает в альбомной, а не в портретной ориентации? Также это имеет ту же проблему, если я не выбираю ориентацию, а затем поворачиваю ее из пейзажа в портрет.

РЕДАКТИРОВАТЬ: Вот мой макет:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <stu.test.project.DrawingSurface
        android:layout_width="fill_parent"
        android:layout_height="700dp"
        android:id="@+id/drawingSurface"/>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">   
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:id="@+id/ButtonRow1"/>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:id="@+id/ButtonRow2"/>
    </LinearLayout>
</LinearLayout>

Вот onCreate для Activity, который вызывает surfaceView, ошибка находится в последней строке, где извлекается дескриптор потока

public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.drawing_layout);  



        // Retrieve STATE and patient number from intent
        bundle = this.getIntent().getExtras();
        STATE = bundle.getInt("state");
        patientString = bundle.getString("patientString");

        //retrieveViews();
        showButtons();

        System.out.println("IN ONCREATE");

        // Setup initial stuff if creating rather than resuming
        if (savedInstanceState==null){
            System.out.println("IN ONCREATE AND NO SIS");
            switch(STATE){
            case STATE_DRAW:
                setupDraw();
                break;
            case STATE_LOAD:
                setupLoad();
                drawLoad();
                break;
            }       
        }

        /* Should put Else in here
         * to maybe resume data from savedInstanceState
         * rather than using onSurfaceCreated as do at moment
         */

        // Retrieve handle to thread
        mThread = drawingSurface.getThread();

      }

А вот класс SurfaceView, не уверенный в том, что имеет значение, поэтому скопировал все это:

public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
private boolean _run;
private Object mPauseLock = new Object();  
private boolean mPaused;
private int STATE;
private static final int STATE_DRAW=1;
private static final int STATE_LOAD=2;
private static final int STATE_PAUSED=4;
private static final int STATE_RESUME_DRAWING=5;
private boolean finishDrawing;
private boolean startedDrawing=true;
private int resetCanvas=0;
private boolean threadRunning;
protected DrawThread thread;
boolean loaded;

public DrawingSurface(Context context, AttributeSet attrs) {
    super(context, attrs);

    getHolder().addCallback(this);
    thread = new DrawThread(getHolder());
}


class DrawThread extends  Thread{
    private SurfaceHolder mSurfaceHolder;
    private List<DrawingPath> mDrawingPaths;
    private List<MyLine> mMyLines, backupLines;
    private Paint mPaint;

    public DrawThread(SurfaceHolder surfaceHolder){
        mSurfaceHolder = surfaceHolder;
        mDrawingPaths = Collections.synchronizedList(new ArrayList<DrawingPath>());
        mMyLines = Collections.synchronizedList(new ArrayList<MyLine>());
    }

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

    public void setBackupLine(List<MyLine> l){
        backupLines = l;
        System.out.println("SETUP BACKLINE SIZE IS: "+backupLines.size());
    }

    // Two methods for your Runnable/Thread class to manage the Thread properly.
    public void onPause() {
        synchronized (mPauseLock) {
            // Only pause if not finished drawing, if finished want to exit thread
            if (!finishDrawing){
            mPaused = true;
            loaded=false;
            }
        }
        System.out.println("Set mPaused = true");
    }

    public void onResume() {
        synchronized (mPauseLock) {
            mPaused = false;
            mPauseLock.notifyAll();
        }
        System.out.println("Set mPaused = false");
//            // Load the saved drawings or reload
//            if (STATE == STATE_DRAW)
//              setState(STATE_RESUME_DRAWING);
//            // If loading then dont change state and instead just restart thread
//            else if (STATE == STATE_LOAD){ 
////                resumeDrawing();
//              setRunning(true); 
//            }

    }

    public boolean needToWait(){
        return finishDrawing||mPaused;
    }

    public void setFinishDrawing(boolean b){
        finishDrawing=b;
    }

    public void setReset(int reset){
        resetCanvas=reset;
    }

    public void addMyLines(List<MyLine> lines){
        mMyLines = lines;
    }

    public void addDrawingPath(DrawingPath drawingPath){

        mDrawingPaths.add( drawingPath );
    }

    public int getSizeDrawingPaths(){
        return mDrawingPaths.size();
    }

    public void setLoadPaint(Paint p){
        mPaint =  p;
    }

    public DrawingPath getDrawingPath(int index){
        return mDrawingPaths.get(index);
    }

    @Override
    public void run() {  
        while (_run){
            // Set variable for running
            threadRunning=true;
            Canvas canvas = null;

            // This code pauses the thread
            synchronized (mPauseLock) {
                while (mPaused) {
                    try {                       
                        mPauseLock.wait();  
                        System.out.println("IN PAUSE LOOP");
                    } catch (InterruptedException e) {
                    }
                }
            }

            try{
                canvas = mSurfaceHolder.lockCanvas(null);

                // Split into DRAW and LOAD

                // DRAW IMAGE FROM PATHS
                if (STATE == STATE_DRAW){
                synchronized(mDrawingPaths) {
                    // If not finished drawing or resetthen draw onto canvas
                    if (!finishDrawing&&resetCanvas==0){
 //                         // Draw screen white
//                          if (startedDrawing){
//                              startedDrawing=false;
//                              canvas.drawColor(Color.WHITE);
//                              System.out.println("DRAWING CANVAS WHITE");
//                              
//                          }
                        doDraw(canvas);
                    }
                    }
                    if (resetCanvas>0){
                        System.out.println("Resetting canvas");
                        if (canvas!=null)
                            canvas.drawColor(Color.WHITE);  
                        resetCanvas--;
                    }                      
                }

                // DRAW IMAGE FROM POINTS
                else if (STATE == STATE_LOAD){
                    doLoad(canvas, mMyLines);
                    // Then close the thread
                    setRunning(false);
                }

                // IF RESUMING FROM DRAWING PAUSE
                else if (STATE == STATE_RESUME_DRAWING){
                    if (!loaded) {
                        doLoad(canvas, backupLines);
                        System.out.println("DID LOAD OF RESUME");
                        setState(STATE_DRAW);
                        loaded=true;
                        //setRunning(false);
                    }
                }
            }
             finally {
                if (canvas!=null){
                    mSurfaceHolder.unlockCanvasAndPost(canvas);
                }
            }                   
        } // While run
    }

    public void doDraw(Canvas c){
        @SuppressWarnings("rawtypes")
            Iterator i = mDrawingPaths.iterator();
        while (i.hasNext()){
            final DrawingPath drawingPath = (DrawingPath) i.next();
            if (c==null)
                System.out.println("CANVAS IS NULL");
            else if (drawingPath.path==null)
                System.out.println("PATH IS NULL");
            else if (drawingPath.paint==null)
                System.out.println("PAINT IS NULL");
            if (c!=null) // Only draw to canvas if it isnt null
                c.drawPath(drawingPath.path, drawingPath.paint);
        }
    }

    public void doLoad(Canvas c, List<MyLine> lines){
        // Loop through the List of lines
        @SuppressWarnings("rawtypes")
            Iterator i = lines.iterator();
        while(i.hasNext()){
            // Get the current line
            final MyLine lineIt = (MyLine) i.next();
            // Create new array of floating points to hold the PointFs from MyLine to draw
            float prevX=0, prevY=0;
            for (int j=0;j<lineIt.getSize()-1;j=j+2){  
                 if (c==null)
                    System.out.println("CANVAS IS NULL");
                if (j!=0&&c!=null){
                    c.drawLine(prevX, prevY, lineIt.getPoint(j).x, lineIt.getPoint(j+1).y, mPaint);
                }
                prevX = lineIt.getPoint(j).x;
                prevY = lineIt.getPoint(j+1).y;
            }   
        }
    }

        public void remove(int i) {
            mDrawingPaths.remove(i);

        }

        public void clearAllPaths(){
            mDrawingPaths.clear();
        }

        public void setState(int s){
            STATE = s;
        }

}


public void addDrawingPath (DrawingPath drawingPath){
    thread.addDrawingPath(drawingPath);
}

public int getSizeDrawingPaths(){
    return thread.getSizeDrawingPaths();
}

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

public void surfaceCreated(SurfaceHolder holder) {
    // only create thread if doesnt exist
    if (!threadRunning){
            thread.setRunning(true);
            thread.setFinishDrawing(false);
            thread.setReset(2); // Set reset to colour screen white
            thread.start();
    }
//      // Resuming is handled in DrawingActivity's onPause override
//      else {  
//          thread.onResume();
//      }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    boolean retry = true;
    // If finished drawing then close thread
    // Else just want to pause thread
//        if (finishDrawing){
//          thread.setRunning(false);
//          while (retry) { 
//                try {
//                    thread.join();
//                    retry = false;
//                    threadRunning = false; // Set threadRunning to false so creates new thread when rejoins
//                } catch (InterruptedException e) {
//                    // we will try it again and again...
//                }
//            }         
//        }
//        else {
//          thread.onPause();
//          System.out.println("Paused thread in SurfaceDestroyed");
//          System.out.println("threadRunning is :"+threadRunning);
//        }


}

    public void remove(int i) {
        thread.remove(i);

    }

    public void getDrawingPath(int i){
        thread.getDrawingPath(i);
    }

    public void clearAllPaths(){
        thread.clearAllPaths();
    }

    public void resetScreen(){
        thread.setReset(2);
    }

    public void addMyLines(List<MyLine> lines){
        thread.addMyLines(lines);
    }

    public void finishDrawing(){
        thread.setFinishDrawing(true);
    }

    public DrawThread getThread(){
        return thread;
    }

    public void resumeDrawing(){
        thread.setFinishDrawing(false);
    }

    public void setState(int s){
        thread.setState(s);
    }

    public void setLoadPaint(Paint p){
        thread.setLoadPaint(p);
    }

    public void pauseThread(){
        thread.onPause();
    }

    public void resumeThread(){
        thread.onResume();
    }

    public boolean getThreadRunning(){
        return threadRunning;
    }
}

1 Ответ

1 голос
/ 09 мая 2012

У вас есть одинаковый файл макета для портретной и альбомной ориентации?

У меня был похожий звуковой пакет сегодня, где у меня был SurfaceView в файле макета портрета, но не в файле макета ландшафта. По какой-то причине он запустился, но когда я повернул устройство, SurfaceCreated | Changed | Destroyed больше не происходило. Поворот назад и все снова было счастливым.

...