在活动之间切换会引发线程错误

时间:2012-09-30 05:15:36

标签: java android sdk

我制作了一个带有两个窗口的应用程序,当我从主窗口转到首选项时,一切都很好,但是当我尝试返回主活动应用程序崩溃时,Thread已经启动错误。

@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。在游戏视图中,我有main,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,因为我发现它与run有关。我仍然试图找出如何使线程(或屏幕?)被破坏然后重新制作它。

公共类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) {
        }
    }
}

}

1 个答案:

答案 0 :(得分:0)

好的就是交易,surfaceCreated()似乎持有一个线程,并且该线程只能启动一次且只能启动一次。这是当前的问题。

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

在不了解应用程序的整个设计的情况下,有几种方法可以多次触发。

可以创建,销毁Surface,然后可以创建新曲面。在这种情况下,GameView将具有相同的线程引用并尝试再次启动它。所以你有SurfaceView的Activity-A。创建Surface,然后启动另一个活动,表面视图可能会在onPause()的周围被销毁。您完成首选项并返回到您的活动,onResume()被调用,您的表面将被重新创建......两次点火。这是假设你的应用程序是这样的: 活动 - &gt; PreferencesActivity - &gt;原始活动。

你似乎开始了另一项任务,所以我不确定你为什么这样做,但旧的活动仍然在后台,所以如果它恢复,它可能会重建表面。

不确定GameManager是什么,但它看起来像某种运行循环。如果已经存在,您可以确保它未启动。或者,如果存在可能需要单独的GameManager实例的情况,您可以跟踪多个实例并确保不再启动它们。