用于在surfaceView中运行线程的IllegalThreadExeption,特定于Lunar Lander示例

时间:2014-11-19 03:30:18

标签: java android multithreading

所以我有一个应用程序,它使用一个表面视图,为UI运行一个单独的线程。它几乎直接来自Lunar Landing示例应用程序。该应用程序还在另一个线程上使用蓝牙服务,但我确信这与问题无关,因为我可以一起禁用蓝牙,但它仍然会发生。

我的应用程序中的问题是,关闭后重新打开的应用程序在thread.start()之后没有开始运行UI线程,除非它抛出错误。在Lunar示例中,他们在onSurfaceCreated方法中有thread.start()。问题是当我重新启动我的应用程序(它调用onPause然后onSurfaceDestroy)时,线程已经在运行,当我尝试启动它时出现错误。我的onSurfaceCreated,onPause,onResume和onSurfaceDestroyed的代码与示例完全相同。我知道我可以使用if (this.getState() == Thread.State.NEW) {,但这似乎会掩盖我的其他一些问题。我想掌握活动生命周期。

我的问题是Lunar Lander如何阻止线程?为什么我没有使用相同的代码停止并在onSurfaceCreated方法上运行。显然我错过了一些东西。据我所知,在Lunar示例中,在破坏线程上调用的唯一内容是thread.join()

编辑3:如果需要,这是Lunar Lander Example Code

所以这些是我的surfaceview中的三种覆盖方法......

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {

    Log.d(TAG, "surfaceCreated");

    // start the bluetooth service
    thread.startBluetoothService();

    // start the game
    //if (this.getState() == Thread.State.NEW) {
        Log.d(TAG, "thread start");
        // start running the thread
        this.start();

    //}

    Log.d(TAG, "running to true");
    // release the thread lock
    setRunning(true);
}

// surfaceChanged is called at least once after surfaceCreated
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    Log.d(TAG, "surfaceChanged");

    // reset the surface size
    thread.setSurfaceSize(width, height);
}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {

    Log.d(TAG, "surfaceDestroyed");

    // make sure to shut down the thread cleanly
    boolean retry = true;

    // stop the running thread
    thread.setRunning(false);

    // continuously try to shut down the thread
    while (retry){
            try{
                // blocks calling thread until termination
                thread.join();

                // stop the bluetooth service
                //thread.stopBluetoothService();

                retry = false;
            }catch(InterruptedException e){
                //try to shut it down again
            }
    }
}

我真的很失落所有这一切。非常感谢任何帮助,谢谢!

编辑:

所以我做了一些测试。当用户点击主页(完全退出应用程序)onPause时,然后onSurfaceDestroy就像我之前说过的那样。然后当它重新启动时,我得到onResume,接着是onSurfaceCreated。我认为我的问题是当你重新进入应用程序时它没有调用onCreate。

还有一些问题...... 什么区别onPause和onDestroy的区别?我认为我的问题是因为onCreate没有被调用,所以我没有新创建的UI线程,看起来它仍在运行。

即使在onPause上线程是否应停止?因为那时我不会被运行onCreate,它会重新实例化线程。这是onCreate代码......

public void onCreate(Bundle savedInstanceState) {
    Log.d(TAG, "onCreate");

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_wobble);

    // get view and thread
    wobbleView = (WobbleView) findViewById(R.id.wobble);
    wobbleThread = wobbleView.getThread();

    // Get local Bluetooth adapter
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

    // If the adapter is null, then Bluetooth is not supported
    if (mBluetoothAdapter == null) {

        // alert the user of bluetooth failure
        Toast.makeText(this, "Bluetooth is not available, using internal devices sensors", Toast.LENGTH_LONG).show();

        // set the data source to internal sensors - so we'll just use the devices accel
        wobbleThread.setDataSource(WobbleThread.INTERNAL_SENSORS);

    // bluetooth is supported so make sure its enabled and
    }else{

        // make sure bluetooth is enabled on the device
        if (!mBluetoothAdapter.isEnabled()) {
            Log.d(TAG, "starting request to enable bluetooth");
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        }

        // all is well with bluetooth - use bluetooth
        Log.d(TAG, "setting bluetooth to bluetooth");
        wobbleThread.setDataSource(WobbleThread.BLUETOOTH);


    }

    // give the LunarView a handle to the TextView used for messages
    wobbleView.setTextView(
            (TextView) findViewById(R.id.text_accel),
            (TextView) findViewById(R.id.game_msg),
            (TextView) findViewById(R.id.text_score),
            (TextView) findViewById(R.id.bluetooth_status)
            );


    if (savedInstanceState == null) {
        // we were just launched: set up a new game
        //wobbleThread.setState(wobbleThread.STATE_READY);
    } else {

        //wobbleThread.setRunning(true);
        // we are being restored: resume a previous game
        //wobbleThread.restoreState(savedInstanceState);
    }
}

编辑2: 一些logcat输出

所以这是我在重新打开应用程序后调用thread.start()时得到的。

11-18 22:50:44.104    4868-4868/com.bme.shawn.wobble E/AndroidRuntime﹕ FATAL EXCEPTION: main
     java.lang.IllegalThreadStateException: Thread already started
            at java.lang.Thread.checkNotStarted(Thread.java:871)
            at java.lang.Thread.start(Thread.java:1025)
            at com.bme.shawn.wobble.WobbleThread.startGame(WobbleThread.java:213)
            at com.bme.shawn.wobble.WobbleView.surfaceCreated(WobbleView.java:94)
            at android.view.SurfaceView.updateWindow(SurfaceView.java:580)
            at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:240)
            at android.view.View.dispatchWindowVisibilityChanged(View.java:7903)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1071)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1289)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1050)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5750)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791)
            at android.view.Choreographer.doCallbacks(Choreographer.java:591)
            at android.view.Choreographer.doFrame(Choreographer.java:561)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:150)
            at android.app.ActivityThread.main(ActivityThread.java:5406)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)

如果我使用thread.getState检查并绕过错误,当我关闭然后重新打开应用程序时,我会得到这个。 (基本上记录所有内容)在这种情况下,当应用程序重新打开时,线程根本没有绘制。这是非常奇怪的,因为没有检查我得到一个错误,说线程已经在运行。

11-18 22:59:13.444    5345-5345/com.bme.shawn.wobble D/WobbleActivity﹕ onPause
11-18 22:59:13.584    5345-5345/com.bme.shawn.wobble D/WobbleView﹕ surfaceDestroyed
11-18 22:59:17.794    5345-5345/com.bme.shawn.wobble D/WobbleActivity﹕ onResume
11-18 22:59:17.804    5345-5345/com.bme.shawn.wobble D/WobbleView﹕ surfaceCreated
11-18 22:59:17.804    5345-5345/com.bme.shawn.wobble D/WobbleThread﹕ running to true
11-18 22:59:17.804    5345-5345/com.bme.shawn.wobble D/WobbleView﹕ surfaceChanged
11-18 22:59:17.804    5345-5345/com.bme.shawn.wobble D/WobbleThread﹕ setting surface sizes
11-18 22:59:17.824    5345-5345/com.bme.shawn.wobble D/dalvikvm﹕ GC_FOR_ALLOC freed 3343K, 2% free 6585K/6668K, paused 13ms, total 13ms
11-18 22:59:17.844    5345-5345/com.bme.shawn.wobble E/IMGSRV﹕ :0: PVRDRMOpen: TP3, ret = 44
11-18 22:59:17.854    5345-5345/com.bme.shawn.wobble E/IMGSRV﹕ :0: PVRDRMOpen: TP3, ret = 50

1 个答案:

答案 0 :(得分:0)

surfaceCreated()中创建一个新线程实例并启动它。并在thread.join()中调用surfaceDestroyed()来销毁它。