Страница 1 из 1

Почему приложение использующее Thread может крашится?

Добавлено: 01 сен 2013, 14:43
Arssir
Пытаюсь сделать анимацию используя Thread и Surface. Сама программа работает нормально, но при закрытии или перезапуске происходит ошибка, из за чего это может происходить?

Код: Выделить всё

public class MainActivity extends Activity {

	private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private float initX, initY;
    private float targetX, targetY;
    private boolean drawing = true;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(new MySurfaceView(this));
    }

    public class MySurfaceThread extends Thread {

        private SurfaceHolder myThreadSurfaceHolder;
        private MySurfaceView myThreadSurfaceView;
        private boolean myThreadRun = false;

        public MySurfaceThread(SurfaceHolder surfaceHolder,
                MySurfaceView surfaceView) {
            myThreadSurfaceHolder = surfaceHolder;
            myThreadSurfaceView = surfaceView;
        }

        public void setRunning(boolean b) {
            myThreadRun = b;
        }

        @SuppressLint("WrongCall")
		@Override
        public void run() {
            // TODO Auto-generated method stub
            // super.run();
            while (myThreadRun) {
            	Canvas canvas = null;
                try {
                	canvas = myThreadSurfaceHolder.lockCanvas(null);
                    synchronized (myThreadSurfaceHolder) {
                        myThreadSurfaceView.onDraw(canvas);
                    }

                    sleep(50);

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    if (canvas != null) {
                        myThreadSurfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }
    
    public class MySurfaceView extends SurfaceView implements
            SurfaceHolder.Callback {

        private MySurfaceThread thread;

        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            // super.onDraw(canvas);
            if (drawing) {
                canvas.drawRGB(00, 00, 00);
                canvas.drawCircle(initX, initY, 3, paint);
                if ((initX == targetX) && (initY == targetY)) {
                    drawing = false;
                } else {
                    initX = (initX + targetX) /2;
                    initY = (initY + targetY) /2;
                }
            }
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            // return super.onTouchEvent(event);
            int action = event.getAction();

            if (action == MotionEvent.ACTION_DOWN) {
                targetX = event.getX();
                targetY = event.getY();
                drawing = true;
            }

            return true;
        }
        

        private void init() {
            getHolder().addCallback(this);
            thread = new MySurfaceThread(getHolder(), this);

            setFocusable(true); // убедиться, что мы получаем ключевые события

            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(3);
            paint.setColor(Color.WHITE);

            initX = targetX = -10;
            initY = targetY = -10;

        }

        public MySurfaceView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
            init();
        }

        public MySurfaceView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
            init();
        }

        public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            // TODO Auto-generated constructor stub
            init();
        }

        @Override
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                int arg3) {
            // TODO Auto-generated method stub
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            thread.setRunning(true);
            thread.start();
        }

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

Re: Почему приложение использующее Thread может крашится?

Добавлено: 02 сен 2013, 09:00
KamiSempai
Что пишет в логах?

Re: Почему приложение использующее Thread может крашится?

Добавлено: 02 сен 2013, 11:30
Arssir
KamiSempai писал(а):Что пишет в логах?
Thread already started.

Какая-то проблема с закрытием и открытием потока.

Re: Почему приложение использующее Thread может крашится?

Добавлено: 02 сен 2013, 14:25
KamiSempai
Все ясно. Проблема в методе surfaceCreated. Дело в том, что при при сворачивании приложения и остановке потока в методе surfaceDestroyed, созданный MySurfaceThread так и остается висеть в MySurfaceView и при разворачивании повторно вызывается surfaceCreated. Только вот поток к которому там идет обращение уже использовался раньше, был запущен и остановлен, а повторно запустить поток нельзя, произойдет исключение, вот оно и происходит.
Следовательно нужно создать новый поток.
Вот работающий пример кода:[syntax=java]public class MainActivity extends Activity {

private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

private float initX, initY;
private float targetX, targetY;
private boolean drawing = true;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new MySurfaceView(this));
}

public class MySurfaceThread extends Thread {

private SurfaceHolder myThreadSurfaceHolder;
private MySurfaceView myThreadSurfaceView;
private boolean myThreadRun = false;

public MySurfaceThread(SurfaceHolder surfaceHolder,
MySurfaceView surfaceView) {
myThreadSurfaceHolder = surfaceHolder;
myThreadSurfaceView = surfaceView;
}

@Override
public void interrupt() {
super.interrupt();
myThreadRun = false;
}

@SuppressLint("WrongCall")
@Override
public void run() {
// TODO Auto-generated method stub
// super.run();
myThreadRun = true;
while (myThreadRun) {
Canvas canvas = null;
try {
canvas = myThreadSurfaceHolder.lockCanvas(null);
if(canvas != null)
synchronized (myThreadSurfaceHolder) {
myThreadSurfaceView.onDraw(canvas);
}

sleep(50);

} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (canvas != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}

public class MySurfaceView extends SurfaceView implements
SurfaceHolder.Callback {

private MySurfaceThread thread;

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
// super.onDraw(canvas);
if (drawing) {
canvas.drawRGB(00, 00, 00);
canvas.drawCircle(initX, initY, 3, paint);
if ((initX == targetX) && (initY == targetY)) {
drawing = false;
} else {
initX = (initX + targetX) /2;
initY = (initY + targetY) /2;
}
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
// return super.onTouchEvent(event);
int action = event.getAction();

if (action == MotionEvent.ACTION_DOWN) {
targetX = event.getX();
targetY = event.getY();
drawing = true;
}

return true;
}


private void init() {

getHolder().addCallback(this);
setFocusable(true); // убедиться, что мы получаем ключевые события

paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setColor(Color.WHITE);

initX = targetX = -10;
initY = targetY = -10;

}

public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
init();
}

public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init();
}

public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
init();
}

@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
if(thread == null) {
thread = new MySurfaceThread(holder, this);
thread.start();
}
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.interrupt();
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
thread = null;
}
}
} [/syntax]

Re: Почему приложение использующее Thread может крашится?

Добавлено: 03 сен 2013, 18:56
Arssir
Спасибо, все получилось, больше не выдает ошибку. Но только теперь приложение при сворачивании вообще никогда не закрывается.

Re: Почему приложение использующее Thread может крашится?

Добавлено: 03 сен 2013, 22:04
Foenix
Это особенность ОС АНДРОИД.

Re: Почему приложение использующее Thread может крашится?

Добавлено: 03 сен 2013, 22:54
KamiSempai
Arssir писал(а):Спасибо, все получилось, больше не выдает ошибку. Но только теперь приложение при сворачивании вообще никогда не закрывается.
В смысле? Нажали Home - свернули, нажали назад - закрыли.

Re: Почему приложение использующее Thread может крашится?

Добавлено: 04 сен 2013, 03:01
Arssir
KamiSempai писал(а):
Arssir писал(а):Спасибо, все получилось, больше не выдает ошибку. Но только теперь приложение при сворачивании вообще никогда не закрывается.
В смысле? Нажали Home - свернули, нажали назад - закрыли.
Я открываю приложение, провожу манипуляции с графикой, что-то меняется, я закрываю приложение, открываю его заново, изменения остаются. Картинка не обнуляется до исходного положения.

Re: Почему приложение использующее Thread может крашится?

Добавлено: 04 сен 2013, 13:05
KamiSempai
Arssir писал(а):Я открываю приложение, провожу манипуляции с графикой, что-то меняется, я закрываю приложение, открываю его заново, изменения остаются. Картинка не обнуляется до исходного положения.
Значит вы не закрываете а сворачиваете.