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 以简化界面的交互部分。

我遇到的问题是,虽然这个实现在我第一次运行应用程序时运行良好,但当用户通过按下 Quit 按钮(我调用完成())退出或按下设备上的后退按钮时,我不能重新运行应用程序。再次按应用程序图标会打开一个带有标题栏的空白应用程序,然后按此屏幕上的返回按钮没有任何效果(我需要按主页按钮退出)。

如果我使用:

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 回答