1

私はstackoverflowとAndroid開発が初めてです。Google を使用して Android の質問に対する回答を検索するたびに、ここに誘導されるようです。

ウェルカム画面で始まるシンプルなアプリがあります。ユーザーが再生ボタンを押すと、次のメソッドが呼び出されます。

public void onClickPlay(View v)
{
    finish();
    Intent intent = new Intent();
    intent.setClassName("ca.mytest.player", "ca.mytest.player.GameActivity");
    startActivity(intent);
}

クラス GameActivity (Activity を拡張する) では、以下を使用します。

setContentView(R.layout.game)

このレイアウトは次のようになります。

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

<ca.mytest.player.GamePanel
 android:id="@+id/gamePanel"
 android:layout_width="fill_parent"
 android:layout_height="768px"/>

<Button
 android:id="@+id/quitButton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:onClick="onClickQuit"
 android:layout_alignParentBottom="true"
 android:text="Quit" />

<Button
 android:id="@+id/decoyButton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:layout_above="@+id/quitButton"
 android:onClick="onClickDecoy"
 android:text="Decoy" />

<Button
 android:id="@+id/hideButton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:layout_above="@+id/decoyButton"
 android:onClick="onClickHide"
 android:text="Hide" />

<Button
 android:id="@+id/shootButton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:layout_above="@id/hideButton"
 android:onClick="onClickShoot"
 android:text="Assassinate" />

 <TextView
  android:id="@+id/status"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="Test of text view"
  android:layout_above="@id/shootButton"
 />

</RelativeLayout>

私はこのアプローチを選択しました (インターフェイスのインタラクティブな部分を簡素化するために、xml レイアウトを使用したカスタム SurfaceView.

私が抱えている問題は、この実装はアプリを初めて実行したときに正常に動作しますが、ユーザーが終了ボタン (finish() を呼び出す場所) を押して終了したり、デバイスの [戻る] ボタンを押したりすると、できないことです。アプリを再実行します。アプリ アイコンをもう一度押すと、空白のアプリが開き、タイトル バーが表示されます。この画面で [戻る] ボタンを押しても効果はありません (終了するには、ホーム ボタンを押す必要があります)。

私が使用する場合:

setContentView(new GamePanel(this))

それ以外の:

setContentView(R.layout.game)

つまり、onTouch() イベントでカスタム SurfaceView を使用して finish() を呼び出すだけで、アプリは適切に動作します (必要に応じて何度でも停止および再起動できます)。

GamePanel クラスのコードは次のとおりです。

package ca.mytest.player;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;

public class GamePanel extends SurfaceView implements SurfaceHolder.Callback
{
    private static final String TAG = GamePanel.class.getSimpleName();
    //private Context context;
    private GameThread thread;
    private final float dotSize = 20.0f;
    private final int numberOfButtons = 4;
    private ActionButton[] actionButtons;
    private WindowManager windowManager;

    public GamePanel(Context context)
    {
        super(context);
        init(context);
    }

    public GamePanel(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init(context);
    }

    public GamePanel(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context)
    {
        Log.d(TAG, "*********************************");
        Log.d(TAG, "Creating Game Panel");
        Log.d(TAG, "*********************************");

        // add callback (this) to surface holder to intercept events
        getHolder().addCallback(this);

        // make the GamePanel focusable so it can handle events
        setFocusable(true);

        windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

        actionButtons = new ActionButton[numberOfButtons];

        thread = new GameThread(getHolder(), this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder)
    {
        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder)
    {
        boolean retry = true;

        while(retry)
        {
            try
            {
                thread.join();
                retry = false;
            }
            catch (InterruptedException e)
            {
                Log.d(TAG, "surface destroyed");
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        if (event.getAction() == MotionEvent.ACTION_DOWN)
        {
            if (event.getY() > getHeight() - 50)
            {
                thread.setRunning(false);
                ((Activity)getContext()).finish();
            }
            else
            {
                Log.d(TAG, "Coords: x = " + event.getX() + " ,y = " + event.getY());
            }
        }

        return super.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        canvas.drawColor(Color.BLACK);

        drawGameCircle(canvas);
    }

    private void drawGameCircle(Canvas canvas)
    {
        // Find centre of game circle
        // Game circle fits in a square at far right, full height of display
        float x = (float)(getWidth()/2);
        float y = (float)(getWidth()/2);

        float radius = (float)(getWidth()/2);

        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(x, y, radius, paint);

        // Draw dot for player
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(x, y, dotSize, paint);

        // draw a horizontal line to show game area
        canvas.drawLine(0, 767, 600, 767, paint);
    }

}

私の実装に根本的な問題がありますか? どんな助けでも大歓迎です。ありがとう。

4

1 に答える 1

0

ああ、この問題。何が間違っているのかを理解する前に、私は自分でこの問題に数回遭遇しました。

問題は、クラス全体の実行が終了したときにのみfinish() が呼び出されるため、スレッドがシャットダウンすることです。

ただし、thread.join() の呼び出しが完了するまで、finish() は呼び出されないため、デッドロック状態が発生します。

推奨されるアクションが何かはわかりませんが、thread.join() を呼び出す直前に、surfaceDestroyed() メソッドでスレッドを終了することをお勧めします。

こうすることで、待機する前に処理を終了するようにスレッドに指示します。

于 2011-10-08T04:28:16.400 に答える