Недавно я с программирования приложений на java для android перешёл на игры. И тут же возникла очень большая проблема: при первом заходе в игру всё нормально, но если нажать кнопку "назад" или "домой", не закрывая окна, а затем снова открыть игру, в ней ничего нет - только пустое окно. Чего я только не перепробовал - ничего не получилось. Я начинающий девелопер, и прошу не судить за мою тупость, если таковая имеет место быть.
Код:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new DrawView(this));
}
class DrawView extends SurfaceView implements SurfaceHolder.Callback{
private DrawThread drawThread;
private Player player;
public DrawView(Context context) {
super(context);
getHolder().addCallback(this);
drawThread = new DrawThread(getHolder(),this);
player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.player), 10, 10);
setFocusable(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
drawThread.setRunning(true);
drawThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void onDraws(Canvas canvas){
canvas.drawColor(Color.rgb(0, 80, 0));
player.draws(canvas);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry){
try {
drawThread.join();
retry = false;
} catch (InterruptedException e) {}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
player.handleActionDown((int) event.getX(), (int) event.getY());
}
if (event.getAction() == MotionEvent.ACTION_MOVE){
if (player.isTouched()){
player.setX((int) event.getX());
player.setY((int) event.getY());
}
}
if (event.getAction() == MotionEvent.ACTION_UP){
if (player.isTouched) player.setTouched(false);
}
return true;
}
}
class DrawThread extends Thread {
private boolean running = false;
private SurfaceHolder surfaceHolder;
private DrawView drawView;
public DrawThread(SurfaceHolder surfaceHolder, DrawView drawView){
this.surfaceHolder = surfaceHolder;
this.drawView = drawView;
}
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
Canvas canvas;
while (running){
canvas = null;
try {
canvas = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
if (canvas == null) continue;
drawView.onDraws(canvas);
}
}finally {
if (canvas != null) surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
class Player{
private Bitmap bitmap;
private int x;
private int y;
private boolean isTouched;
public Player(Bitmap b, int x, int y){
this.bitmap = b;
this.y = y;
this.x = x;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setTouched(boolean touched) {
isTouched = touched;
}
public boolean isTouched() {
return isTouched;
}
public void draws(Canvas canvas){
canvas.drawBitmap(bitmap, x - bitmap.getWidth()/2, y - bitmap.getHeight()/2, null);
}
public void handleActionDown(int eventX, int eventY){
if (eventX >= x - bitmap.getWidth() / 2 && eventX <= x + bitmap.getWidth() / 2 &&
eventY >= y - bitmap.getHeight() / 2 && eventY <= y + bitmap.getHeight() / 2) setTouched(true);
else setTouched(false);
}
}
}
surfaceDestroyed
вызывается каждый раз, когда SurfaceView
перестаёт быть виден на экране. В нём Вы завершаете поток рисования. Но один экземпляр потока может быть запущен только один раз. Когда он завершился, то запустить его повторно нельзя - нужно создавать новый экземпляр:
@Override
public void surfaceCreated(SurfaceHolder holder) {
drawThread = new DrawThread(getHolder(),this);
drawThread.setRunning(true);
drawThread.start();
}
P.S. Не знаю зачем Вам эта конструкция:
while (retry){
try {
drawThread.join();
retry = false;
} catch (InterruptedException e) {}
}
но останавливать любым способом и сильно нагружать главный поток на Андроиде крайне нежелательно.
P.P.S. А проблема то как раз ещё и в этой конструкции - она блокирует главный поток и ждёт завершения рисующего, но рисующий не останавливается так как ему не вызван drawThread.setRunning(false);
и он даже не знает что надо прекратить работу. В результате главный поток не может ни завершить ни восстановить работу активити
Во первых, я бы избавился от анонимности DrawView и перенес бы его в разметку.
<com.example.DrawView
android:id="@+id/draw_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Затем в активити определил бы его.
public class MainActivity extends AppCompatActivity {
private DrawView drawView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dravView = findViewById(R.id.draw_view);
}
}
Далее внес бы изменения в само DrawView
class DrawView extends SurfaceView implements SurfaceHolder.Callback{
//ваши поля
/*без этого конструктора в разметке ваше View не разместить*/
public DrawView(Context context,@Nullable AttributeSet attrs) {
super(context,attrs);
}
/*этим методом все запускаете*/
public voyd play(){
getHolder().addCallback(this);
drawThread = new DrawThread(getHolder(),this);
player = new Player(BitmapFactory.decodeResource(getResources(),
R.drawable.player), 10, 10);
setFocusable(true);
{
//остальной код
}
В MainActivity переопределяем onStart()
@Override
protected void onStart() {
super.onStart();
drawView.play();
}
Вроде так. На машине не тестил, но должно помочь. Хотя в принципе, при нажатии кнопки Back то таких нюансов не должно было быть..
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Хочу сделать так что бы JS определял Ip пользователя при запуске скрипта, но не знаю как это сделатьПодскажете?
Столкнулась с проблемой, что изображение, получаемое из canvas, не добавляется в поле imageКод следующий (VueJS v