0

2つのウィンドウでアプリを作成します。メインウィンドウから設定に移動すると、すべて問題ありませんが、メインアクティビティに戻ろうとすると、スレッドが既に開始されているというエラーでアプリがクラッシュします。

@Override
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(new GameView(this));
    startService(new Intent(this, MyService.class));

}

public void onResume(){
    super.onResume();

}
// Initiating Menu XML file (menu.xml)
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater menuInflater = getMenuInflater();
    menuInflater.inflate(R.layout.menu, menu);
    return true;
}

public void onBackPressed() {
    super.onBackPressed();
    stopService(new Intent(this, MyService.class));
    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_HOME);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
}

更新:LogCatからのログは次のとおりです(私はEclipseを使用しています):

09-30 11:59:17.348: D/AndroidRuntime(2917): Shutting down VM
09-30 11:59:17.348: W/dalvikvm(2917): threadid=1: thread exiting with uncaught exception (group=0x40aa7210)
09-30 11:59:17.368: E/AndroidRuntime(2917): FATAL EXCEPTION: main
09-30 11:59:17.368: E/AndroidRuntime(2917): java.lang.IllegalThreadStateException: Thread already started.
09-30 11:59:17.368: E/AndroidRuntime(2917):     at java.lang.Thread.start(Thread.java:1045)
09-30 11:59:17.368: E/AndroidRuntime(2917):     at com.examples.todolist.GameView$1.surfaceCreated(GameView.java:45)

ManiFestファイル(それからのアクティビティ):

<application

    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <service 
        android:name="MusicService"
        android:enabled="true">

    </service>
    <activity

        android:name=".MainActivity"
        android:label="@string/title_activity_main" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name="PreferencesActivity"></activity>
    <service android:enabled="true" android:name=".MyService" />
</application>

私のプロジェクトには、MainActivity.java(メインウィンドウ)、PreferencesActivity.java(設定ウィンドウ)、GameView.java(描画を担当)、GameManager.java(FPSを制御)があります。ゲームビューでは、メインイベント、onDrawイベント、onTouchイベントがあります。GameViewのメインは次のとおりです。

public GameView(Context context) {
    super(context);
    gameLoopThread = new GameManager(this);
    holder = getHolder();
    holder.addCallback(new SurfaceHolder.Callback() {
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            gameLoopThread.setRunning(false);
            while (retry) {
                try {
                    gameLoopThread.join();
                    retry = false;
                } catch (InterruptedException e) {
                }
            }
        }

        public void surfaceCreated(SurfaceHolder holder) {
            gameLoopThread.setRunning(true);
            gameLoopThread.start();
        }

        public void surfaceChanged(SurfaceHolder holder, int format,
                int width, int height) {
        }
    });
    bmp = BitmapFactory.decodeResource(getResources(),
            R.drawable.ic_launcher);
    bmp1 = BitmapFactory.decodeResource(getResources(),
            R.drawable.wall_sprite);
}

これがgameManager.javaです。これは、実行と関係があることがわかったためです。私はまだスレッド(またはスクリーン?)を破壊してから再び作る方法を理解しようとしています。

パブリッククラスGameManagerはスレッドを拡張します{

static final long FPS = 30;

private GameView view;

private boolean running = false;

// class constructor
public GameManager(GameView view) {
    this.view = view;
}

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

public void run() {
    long ticksPS = 1000 / FPS;
    long startTime;
    long sleepTime;
    while (running) {
        Canvas c = null;
        startTime = System.currentTimeMillis();
        try {
            c = view.getHolder().lockCanvas();
            synchronized (view.getHolder()) {
                view.onDraw(c);
            }
        } finally {
            if (c != null) {
                view.getHolder().unlockCanvasAndPost(c);
            }
        }
        sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
        try {
            if (sleepTime > 0)
                sleep(sleepTime);
            else
                sleep(10);
        } catch (Exception e) {
        }
    }
}

}

4

1 に答える 1

0

これが取引です。surfaceCreated()はスレッドを保持しているようで、そのスレッドは1回だけ開始できます。それが当面の問題です。

public void surfaceCreated(SurfaceHolder holder) {
            gameLoopThread.setRunning(true);
            // This is unsafe
            gameLoopThread.start();
}

アプリの全体的なデザインを知らなくても、これを複数回トリガーする方法はいくつかあります。

サーフェスを作成、破棄してから、新しいサーフェスを作成できます。この場合、GameViewは同じスレッド参照を持ち、それを再起動しようとします。つまり、SurfaceViewを使用したActivity-Aがあります。サーフェスを作成してから、別のアクティビティを開始すると、onPause()の前後にサーフェスビューが破棄される可能性があります。環境設定を終了してアクティビティに戻ると、onResume()が呼び出され、サーフェスが再作成されます...2回起動します。これはすべて、アプリが次のようになることを前提としています:アクティビティ->設定アクティビティ->元のアクティビティ。

別のタスクを開始しているように見えるので、なぜそれを行うのかわかりませんが、古いアクティビティはまだバックスタックにあるため、再開すると、おそらくサーフェスが再作成されます。

GameManagerが何に必要かはわかりませんが、ある種の実行ループのように見えます。すでに開始されている場合は、開始されていないことを確認できます。または、個別のGameManagerインスタンスが必要になる場合がある場合は、複数のインスタンスを追跡し、それらを再起動しないようにすることができます。

于 2012-10-01T00:29:31.297 に答える