2012-02-28 61 views
1

我正在使用一個線程來運行5秒的計時器,當計時器耗盡時,我想更改一些變量並重新啓動它,重複此過程直到不滿足某個條件。我一直在研究線程,顯然他們不能重置或再次使用,但必須創建另一個線程。我無法弄清楚正確的方法。線程可以在Android中重複使用嗎?

這裏是我的代碼:

package com.deucalion0; 

import android.app.Activity; 
import android.content.Intent; 
import android.media.MediaPlayer; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.Button; 
import android.widget.TextView; 

public class FirstOneActivity extends Activity { 
/** Called when the activity is first created. */ 


MediaPlayer ourSong; 
int counter; 
Button add; 
Thread timer; 
TextView display; 
TextView lvl; 
int level = 1; 
int time; 




@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    ourSong = MediaPlayer.create(FirstOneActivity.this, R.raw.click); 
    counter = 0; 
    add = (Button) findViewById (R.id.bAdd); 
    display = (TextView) findViewById (R.id.tvDisplay); 
    lvl = (TextView) findViewById (R.id.lvldisplay); 

    add.setOnClickListener(new View.OnClickListener() { 

     public void onClick(View v) { 
      // TODO Auto-generated method stub 
      counter++; 
      //ourSong.start(); 
      display.setText("Your total is "+ counter); 

      if(counter ==1) 

      { 
       set(); 
      } 
     } 
    }); 


    timer = new Thread(){ 
     public void run(){ 
      try{ 
       sleep(time); 
      }catch(InterruptedException e){ 
       e.printStackTrace(); 
      }finally{ 
       test(); 

      } 
     } 


    }; 

} 


public void test(){ // Method that does two things after the timer runs out, depending on the value held in counter 

if(counter>= 10 && level == 1 || counter>= 15 && level == 2) 
    {  
     level++; 
     counter =0; 
     display.setText("Your total is 0"); 

     //The timer must be reset for the next level 


    } 

    else if(counter<10 && level == 1 || counter< 15 && level == 2){ 

     Intent openNext = new Intent("com.deucalion0.NEXT"); 
     startActivity(openNext); 
    } 


} 


public void set(){ 


     if(level == 1) 
    { lvl.setText("Level is "+ level); 
     time = 5000; // The value passed to the sleep method in the thread, this is the length of the timer 
    } 

    else if (level == 2) 
    {lvl.setText("Level is "+level); 
     time = 5000; 
    } 

} 


} 

所以基本上我想繼續使用線程,但它傳遞根據水平不同的時間限制,爲了測試我只編程現在前兩個級別。

我將不勝感激這個。謝謝。

我的代碼修改後的版本起訴一些在這裏的答案,得到的幫助,但我仍然有問題:計數器= 1,當

package com.deucalion0; 

import android.app.Activity; 
import android.content.Intent; 
import android.media.MediaPlayer; 
import android.os.Bundle; 
import android.os.Handler; 
import android.view.View; 
import android.widget.Button; 
import android.widget.TextView; 

public class FirstOneActivity extends Activity { 
/** Called when the activity is first created. */ 


MediaPlayer ourSong; 
int counter; 
Button add; 
Thread timer; 
TextView display; 
TextView lvl; 
int level = 1; 
int time; 
boolean completed = false; 


@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    ourSong = MediaPlayer.create(FirstOneActivity.this, R.raw.click); 
    counter = 0; 
    add = (Button) findViewById (R.id.bAdd); 
    display = (TextView) findViewById (R.id.tvDisplay); 
    lvl = (TextView) findViewById (R.id.lvldisplay); 

    add.setOnClickListener(new View.OnClickListener() { 

     public void onClick(View v) { 
      // TODO Auto-generated method stub 
      counter++; 
      completed=false; 
      //ourSong.start(); 
      display.setText("Your total is "+ counter); 

      if(counter ==1) 

      { 
       set(); 
       timer.start(); // start the timer loop: 
      } 
     } 
    }); 


    // create a Handler for the thread to use when interacting with the UI 
    final Handler handler = new Handler(); 

    // create the timer object 
    timer = new Thread() { 
     public void run() { 
      // create a Runnable that will execute on the UI thread 
      Runnable updater = new Runnable() { 
       public void run() { 

       } 
      }; 

      while (!completed) { 
       try { 
        sleep(time); 
       } catch(InterruptedException e) { 
        e.printStackTrace(); 
       } finally { 
        handler.post(updater); 
        test(); 
       } 
      } 
     } 
    }; 




} 

public void reset()//Resets the variables so the level increments, the counter is reset to 0 
{ 
    completed=true; 
    level++; 
    counter =0; 

} 


public void test(){ // Method that does two things after the timer runs out, depending on the value held in counter 

if(counter>= 10 && level == 1 || counter>= 15 && level == 2) 
    { 
     reset();  
    } 

    else if(counter<10 && level == 1 || counter< 15 && level == 2){ 

     Intent openNext = new Intent("com.deucalion0.NEXT"); 
     startActivity(openNext); 
    } 
} 


public void set(){ 


     if(level == 1) 
    { lvl.setText("Level is "+ level); 
     time = 5000; // The value passed to the sleep method in the thread, thi is the length of the timer 
    } 

    else if (level == 2) 
    {lvl.setText("Level is "+level); 
     time = 5000; 
    } 
} 
} 

遊戲運行和啓動計時器,但如果在計時器用完之後按下按鈕,由於例外情況,我會強行關閉。我需要發生的是計數器重置爲0,如果在5秒內按下超過9次點擊,級別變爲2。以下是LogCat中的錯誤:

02-29 09:47:36.313: D/AndroidRuntime(279): Shutting down VM 
02-29 09:47:36.313: W/dalvikvm(279): threadid=1: thread exiting with uncaught exception  (group=0x4001d800) 
02-29 09:47:36.333: E/AndroidRuntime(279): FATAL EXCEPTION: main 
02-29 09:47:36.333: E/AndroidRuntime(279): java.lang.IllegalThreadStateException:  Thread already started. 
02-29 09:47:36.333: E/AndroidRuntime(279): at java.lang.Thread.start(Thread.java:1322) 
02-29 09:47:36.333: E/AndroidRuntime(279): at com.deucalion0.FirstOneActivity$1.onClick(FirstOneActivity.java:51) 
02-29 09:47:36.333: E/AndroidRuntime(279): at android.view.View.performClick(View.java:2408) 
02-29 09:47:36.333: E/AndroidRuntime(279): at android.view.View$PerformClick.run(View.java:8816) 
02-29 09:47:36.333: E/AndroidRuntime(279): at android.os.Handler.handleCallback(Handler.java:587) 
02-29 09:47:36.333: E/AndroidRuntime(279): at android.os.Handler.dispatchMessage(Handler.java:92) 
02-29 09:47:36.333: E/AndroidRuntime(279): at android.os.Looper.loop(Looper.java:123) 
02-29 09:47:36.333: E/AndroidRuntime(279): at android.app.ActivityThread.main(ActivityThread.java:4627) 
02-29 09:47:36.333: E/AndroidRuntime(279): at java.lang.reflect.Method.invokeNative(Native Method) 
02-29 09:47:36.333: E/AndroidRuntime(279): at java.lang.reflect.Method.invoke(Method.java:521) 
02-29 09:47:36.333: E/AndroidRuntime(279): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 
02-29 09:47:36.333: E/AndroidRuntime(279): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 
02-29 09:47:36.333: E/AndroidRuntime(279): at dalvik.system.NativeStart.main(Native Method) 

我希望這些信息可以幫助顯示我的問題。

回答

2

作爲一般規則,Thread對象可以是任意多次。每撥打start()將啓動一個新線程。其他類似線程的對象(例如,AsyncTask,TimerTask)通常只能執行一次。

但是,您的計時器線程不會按寫入的方式工作。 test()方法修改顯示並需要在UI線程上運行。

一種方法是創建一個Handler,並從計時器線程發佈Runnable到處理程序,該處理程序又調用test()。還有其他方法,但是這可能涉及對現有代碼的最小修改。

你應該看看使用AsyncTask做你想做的。您還應該在開發過程中啓用StrictMode以幫助檢測任何線程錯誤。

這是你的代碼的簡單修改,會做你想要做的我想:

// create a Handler for the thread to use when interacting with the UI 
final Handler handler = new Handler(); 

// create the timer object 
timer = new Thread() { 
    public void run() { 
     // create a Runnable that will execute on the UI thread 
     Runnable updater = new Runnable() { 
      public void run() { 
       test(); 
      } 
     } 
     while (!exitConditionMet()) { 
      try { 
       sleep(time); 
      } catch(InterruptedException e) { 
       e.printStackTrace(); 
      } finally { 
       handler.post(updater); 
      } 
     } 
    } 
}; 

// start the timer loop: 
timer.start(); 

上面的代碼假定有一個方法exitConditionMet()返回true當線程應該退出。

+0

我對Android和一般線程都很缺乏經驗,請問您可以指出一個例子嗎?謝謝! – deucalion0 2012-02-28 17:54:55

+1

@ deucalion0 - 我用一些示例代碼更新了我的答案 – 2012-02-28 18:05:17

+0

非常感謝,我現在嘗試使用它並希望實現我的目標,我會讓我知道我是否可以弄明白。謝謝。 – deucalion0 2012-02-28 19:03:51

1

你應該避免創建和銷燬這樣的線程。對於你的用例,我會說保持同一個線程運行會更好,但在更改變量時使用同步原語來阻止它,然後在你準備好時恢復工作。你可以使用任何從簡單的鎖到條件變量,或任何其他同步機制,但我會保持相同的線程。

+0

所以我仍然可以在運行同一個線程時爲sleep()賦值一個新值?我將查找同步原語。 謝謝。 – deucalion0 2012-02-28 17:56:09

1

不用擔心直接創建和重新使用線程。而是專注於您想要執行的任務,並讓Executor負責爲您安排這些任務(通常使用一組線程)。 Executors類具有許多用於創建不同類型的Executor實例的靜態方法,http://developer.android.com/reference/java/util/concurrent/Executors.html

您可以使用Runnable或AsyncTask來定義您的任務。這裏是如何使用AsyncTask來做這個粗略的例子:

Executor executor = ... 
AsyncTask task = ... 
task.executeOnExecutor(executor, ...); 
+0

我想你是指AsyncTask.executeOnExecutor(),它只有API槓桿11後纔可用。 – yorkw 2012-02-28 20:44:31

+0

你是對的。我已經更新了這個例子。如果你不能使用AsyncTask,你仍然可以使用常規的Runnable來完成,AsyncTask只是讓你更容易。 – 2012-02-29 15:28:32

相關問題