0

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

@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,因为我发现它与运行有关。我仍然试图弄清楚如何使线程(或屏幕?)被破坏,然后再做一次。

公共类 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

Ok here is the deal, surfaceCreated() seems to hold a thread, and that thread can only be started once and only once. That is the immediate issue.

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

Without knowing the entire design of your app there are a few ways this can be triggered multiple times.

A Surface can be created, destroyed and then a new surface can be created. In this case, the GameView would have the same thread reference and try to start it again. So you have Activity-A with SurfaceView. Creates Surface, then you start another activity, your surface view will probably be destroyed around the time of the onPause(). You finish your Preferences and come back to your activity, onResume() gets called and your surface will be recreated ... firing twice. This is all assuming that your app goes something like this: Activity -> PreferencesActivity -> original Activity.

You seem to start another task so I am unsure why you do that, but the old activity is still on the backstack, so if it resumes, it will probably recreate the surface.

Not sure what GameManager is required for but it looks like a run loop of some sort. You can either make sure it isn't started if it already is. Or if there is a case where there may be desired separate GameManager instances, you could keep track of multiple instances and make sure not to start them again.

于 2012-10-01T00:29:31.297 回答