I am using a thread to run a timer of 5 seconds, when that timer runs out I want to change a few variables and start it again, repeating this process until a certain condition is not met. I have been researching threads and apparently they cannot be reset or used again, but another thread must be created instead. I cannot figure out the correct way.
Here is my code:
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;
}
}
}
So basically I want keep using the thread but pass it a different time limit depending on the level, for testing I only the first two levels programmed for now.
I would appreciate any insight into this.Thanks.
A revised version of my code suing some of the help received in the answers here, but I am still having issues:
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;
}
}
}
The game runs and the timer is started when the counter = 1, but if I press the button after the timer runs out, I get a force close due to an exception. What I need to happen is that the counter is reset to 0 and the level becomes 2 if more than 9 clicks were pressed within 5 seconds. Here are the errors in 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)
I hope this information helps show my issues.
As a general rule, a
Threadobject can bestart()-ed as many times as you like. Each call tostart()will launch a new thread. Other thread-like objects (e.g.,AsyncTask,TimerTask) can generally only be executed once.However, your timer thread won’t work as written. The
test()method modifies the display and needs to be run on the UI thread.One approach is to create a
Handlerand from the timer thread post aRunnableto the handler that in turn callstest(). There are other approaches as well, but this one probably involves the least modification to your existing code.You should look at using an
AsyncTaskfor doing what you want. You should also enableStrictModewhile developing to help detect any threading errors.Here’s a simple modification of your code that will do what I think you’re trying to do:
The above code assumes that there’s a method
exitConditionMet()that returnstruewhen the thread should exit.