Sorry for my english. I have timer and i wand if i click timer is on if i click again timer off. But my timer on only one time. If i click again(off timer) i have exception like this:
E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.IllegalStateException: Timer was canceled
at java.util.Timer.scheduleImpl(Timer.java:561)
at java.util.Timer.schedule(Timer.java:481)
at installation.ConnectDevice.callAsynchronousTask(ConnectDevice.java:211)
at installation.ConnectDevice$1.onClick(ConnectDevice.java:153)
at android.view.View.performClick(View.java:4240)
...
I dont know why its not work, please help. Below my class
My class
private Timer timer;
int time = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.i_connect_device);
timer = new Timer();
// my botton
includeDevice.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (time < 1) {
callAsynchronousTask();
time++;
}
if (time > 0) {
stopTimer();
time--;
}
}
});
}
public void callAsynchronousTask() {
final Handler handler = new Handler();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
Log.e("Timer is work", "Timer is work");
// GetMsgs performBackgroundTask = new GetMsgs();
// PerformBackgroundTask this class is the class
// that extends AsynchTask
// performBackgroundTask.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 1000 * 10); // execute in every
// 50000 ms
}
public void stopTimer() {
timer.cancel();
}
Change onClick logic as follows (because in your case at the first time only executed callAsynchronousTask() and stopTimer(). so it raises exception at next onClick)
btnTimer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (time == 0) {
callAsynchronousTask();
time = 1;
} else {
stopTimer();
time = 0;
}
}
});
and doAsynchronousTask make it as field and cancel task on stopTimer().
public void stopTimer() {
doAsynchronousTask.cancel();
}
then it works fine.
From Javadocs:
cancel() : Terminates this timer, discarding any currently scheduled tasks. [...] Once a timer has been terminated, its execution thread terminates gracefully, and no more tasks may be scheduled on it.
and
schedule(Task task, long delay)
throws:
IllegalStateException - if task was already scheduled or cancelled, timer was cancelled, or timer thread terminated.
So basically, your class tells you that it cannot complete the set task due to the fact that the timer has been cancelled. Something you could try is to make the timer sleep until the button is pressed again, instead of cancelling it completely.
Once you cancel the timer; you cannot start it again because thread is stopped.See the link:Pause the timer and then continue itYou have to maintain the state somehow and recreate timer with the current value
You need an async task it is a class so you can extend it. Public class callAsynchronousTask extends async task
And GetMsgs performBackgroundTask = new GetMsgs();
// PerformBackgroundTask this class is the class that extends Async Taskbar goes into the do in background method
Initialize your timer object inside callAsynchronousTask as shown below.
public void callAsynchronousTask() {
final Handler handler = new Handler();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
Log.e("Timer is work", "Timer is work");
//GetMsgs performBackgroundTask = new GetMsgs();
// PerformBackgroundTask this class is the class that extends AsynchTask
//performBackgroundTask.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
});
}
};
timer=new Timer();
timer.schedule(doAsynchronousTask, 0, 1000*10); //execute in every 50000 ms
}
Also modify your in block because it is executing both if condition .
Use boolean flag instead of int
boolean isTimerRunning;
if (!isTimerRunning) {
callAsynchronousTask();
isTimerRunning=true;
}
else (isTimerRunning) {
stopTimer();
isTimerRunning=false;
}
Related
I'm a beginner in Android programming. I'm trying to display a timer for an upgrade in my game to show how long the upgrade will be activated for. In my collision flag I call Looper.prepare and start my thread class as the logcat suggested I do. How would I get this to run on one looper?
Here is the snippet that starts the thread.
BigGapUpgrade.java
public boolean playerCollectUpgrade(Player player){
if(Rect.intersects(rectangle, player.getRectangle())){
Looper.prepare();
bigGapUpgradeHandler.start();
}
return Rect.intersects(rectangle, player.getRectangle());
}
And here is my thread class
BigGapUpgradeHandler.java
public class BigGapUpgradeHandler extends Thread {
TimerTask scanTask;
Timer timer = new Timer();
#Override
public void run() {
Looper.prepare();
scanTask = new TimerTask() {
public void run() {
}
};
timer.schedule(scanTask, 0, 4000);
CountDownTimer countDownTimer = new CountDownTimer(4000, 100) {
#Override
public void onTick(long l) {
Log.i(TAG, "onTick: ");
}
#Override
public void onFinish() {
timer.cancel();
Log.i(TAG, "onFinish: ");
}
}.start();
Looper.loop();
}
}
After running it I get this error
W/System.err: java.lang.RuntimeException: Only one Looper may be created per thread
--Edit
Here is the solution I came up with.
-- Solution
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
CountDownTimer countDownTimer = new CountDownTimer(5000,100) {
#Override
public void onTick(long millisUntilFinished) {
millis = millisUntilFinished/100;
}
#Override
public void onFinish() {
}
}.start();
}
});
OK, So what you can do is just use a TimerTask. That creates it's own background thread for you do stuff:
// This TimerTask Updates the UI so it needs a reference to the Activity.
static class PowerUpTimerTask extends TimerTask
{
WeakReference<AppCompatActivity> mActivity;
long mInterval;
long mPeriod;
public PowerUpTimerTask(AppCompatActivity activity, long period, long interval)
{
mActivity = new WeakReference<>(activity);
mInterval = interval;
mPeriod = period;
}
#Override
public void run()
{
AppCompatActivity activity = mActivity.get();
if (activity != null)
{
final TextView timerTextView = activity.findViewById(R.id.timerTextView);
mPeriod -= mInterval;
if (mPeriod > 0)
{
// Set time remaining
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
timerTextView.setText(String.valueOf(mPeriod));
}
});
}
else
{
// Out of time...clear the Text and stop the timer task.
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
timerTextView.setText("");
}
});
Log.d(TAG, "Timer done. Canceling.");
cancel();
}
}
else
{
// Cancel this timer task since we don't have a reference to
// the Activity any more.
Log.d(TAG, "Lost reference to Activity. Canceling.");
cancel();
}
}
}
Then you can start your Timer task like so:
...
// Will count down from 10 by 1s.
mPowerUpTimerTask = new PowerUpTimerTask(this, powerUpTime, 1);
// Schedule for every second.
Timer t = new Timer();
t.scheduleAtFixedRate(mPowerUpTimerTask, 1000, 1000);
...
Here is a link to this running sample:
https://github.com/didiergarcia/TimerTaskExample
I think you have to use LocalBroadcastManager for the timing to continuously in loop. Please check below code for for that :-
private void startTimer() {
countDownTimer = new CountDownTimer(Constant.getInstance().ANSWER_TIME_IN_SECOND * 1000, 1000) {
public void onTick(long millisUntilFinished) {
remaininTimeInMillies = millisUntilFinished;
tvTimer.setText(getTime(Integer.parseInt(String.valueOf(millisUntilFinished))));
}
public void onFinish() {
Intent intent = new Intent(Constant.getInstance().TIMER_RECEIVER);
LocalBroadcastManager.getInstance(PatientDetailActivity.this).sendBroadcast(intent);
}
};
countDownTimer.start();
}
private String getTime(int milliSec) {
int minut = 0, second = 0;
minut = milliSec / 60000;
second = (milliSec - (minut * 60000)) / 1000;
String strMinute = "", strSecond = "";
if (minut < 10) {
strMinute = "0" + String.valueOf(minut);
} else {
strMinute = String.valueOf(minut);
}
if (second < 10) {
strSecond = "0" + String.valueOf(second);
} else {
strSecond = String.valueOf(second);
}
return strMinute + ":" + strSecond;
}
#Override
protected void onResume() {
LocalBroadcastManager.getInstance(this).registerReceiver(timerBroadcast, new IntentFilter(Constant.getInstance().TIMER_RECEIVER));
super.onResume();
}
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(timerBroadcast);
super.onDestroy();
}
Thanks and Hope that will help you
I have an activity with 3 buttons: create, start and cancel. Button create creates a new thread, button start runs it and button cancel stops this thread. And my problem is that thread isn't interrupted after calling interrupt method (this action is performed after clicking on cancel button). I know, that in my thread I should check if thread is interrupted or no. I added it, but interrupting still doesn't work. Here's my code:
private View.OnClickListener listener = new View.OnClickListener() {
#SuppressLint("HandlerLeak")
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.create_button:
thread = new Thread(new Runnable() {
#Override
public void run() {
int i;
for (i = 0; i<10;i++){
final int finalI = i;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
}
}, 500*i);
if (thread.isInterrupted()){
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
}
new Handler().postDelayed(new Runnable() {
#SuppressLint("SetTextI18n")
#Override
public void run() {
textCounter.setText("Done!");
}
},(i+1)*500);
}
});
break;
case R.id.start_button:
thread.run();
break;
case R.id.cancel_button:
thread.interrupt();
Log.i(getClass().getSimpleName(), "Cancel Button clicked");
break;
}
}
};
So, why thread isn't interrupted and how can I solve this problem?
Your thread is quickly adding 11 tasks (10 + the last one) to this handler you're creating and then dying. These tasks have a delay, and then the message queue will take care of running the 10 + 1 runnables. To do what you're trying to do you should make the thread to wait 500ms between each loop.
Something similar to this:
thread = new Thread(new Runnable() {
#Override
public void run() {
int i;
for (i = 0; i<10;i++){
final int finalI = i;
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
if (thread.isInterrupted()){
Log.i(getClass().getSimpleName(), "Thread is interrupted");
return;
}
}
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText("Done!");
}
});
}
});
There are many problems with your code
Problem 1: When users click on Create button, you create a new thread, it is not expected behavior as you want, so just create a new thread if it is not created yet or terminated.
Problem 2: When users click on Start button
thread.run();
This line does not start the thread, it just executes the code in run method on calling thread, in this case main/UI thread. To start a thread you must use start method. Make sure you start the thread if it is has been created.
Problem 3: When users click on Cancel button
thread.interrupt();
Because there is no thread started so this line will do nothing.
Problem 4: From your description, you want to use a thread to increase counter on a TextView from 0 to 9 each 0.5 second, then display "Done". Your code is incorrect and contains many redundant.
Solution: You can following this code.
private View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.create_button:
// Only create a new thread if it is not created or it is terminated.
if (thread == null || thread.getState() == Thread.State.TERMINATED) {
thread = new Thread(new Runnable() {
#Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
final int finalI = i;
// This will post a message to main/UI thread.
textCounter.post(new Runnable() {
#Override
public void run() {
textCounter.setText(String.valueOf(finalI));
}
});
// Sleep current thread in 0.5 second before running next step.
Thread.sleep(500);
}
// Display Done after finishing counter.
textCounter.post(new Runnable() {
#SuppressLint("SetTextI18n")
#Override
public void run() {
textCounter.setText("Done!");
}
});
} catch (InterruptedException e) {
// Display Cancelled if the current thread is cancelled.
textCounter.post(new Runnable() {
#SuppressLint("SetTextI18n")
#Override
public void run() {
textCounter.setText("Cancelled!");
}
});
}
}
});
} else {
Toast.makeText(MainActivity.this,
"Thread is already created. No need to create anymore.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.start_button:
// Start thread if it is created.
if (thread != null && thread.getState() == Thread.State.NEW) {
thread.start();
} else {
Toast.makeText(MainActivity.this,
"Thread is not created yet or it is running.",
Toast.LENGTH_SHORT)
.show();
}
break;
case R.id.cancel_button:
// Cancel the thread if it is running.
if (thread != null && thread.isAlive()) {
thread.interrupt();
} else {
Toast.makeText(MainActivity.this,
"Thread is not running yet.",
Toast.LENGTH_SHORT)
.show();
}
break;
}
}
};
I have 2 activity in activity2 i have a timer when activity create timer is started in activity on_Destroy i put timer_task.cancel(); but When opened the activity2 for the second time is create new timer task and not Canceled or destroyed the last timer and 2 timer is while be run in one activity
my code
private TimerTask mTimerTask;
private void doTimerTask(){
nCounter = 4;
qtimer.setMax(20);
if(mTimerTask!=null) {
mTimerTask.cancel();
}
mTimerTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Log.d("Timerrrr",nCounter+"");
if(nCounter<1){
Finished();
}else {
qtimer.setProgress(nCounter);
nCounter--;
}
}
});
}};
// public void schedule (TimerTask task, long delay, long period)
t.schedule(mTimerTask, 0, 1000); //
}
private void stopTask() {
if (mTimerTask != null) {
Log.d("nCounter canceled",nCounter+"");
mTimerTask.cancel();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
mTimerTask.cancel();
MainActivity.this.finish();
}
Try This...
public void stopTimerTask(View v) {
//stop the timer, if it's not already null
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
}
And Where do u call your stopTask() method?
And I suggest don't put mTimerTask.cancel(); in onDestroy(), but put it in onStop().
I hope this helps you.
I have a button listener witch include a thread sleep and another button listener.
Second button listener must interrupt this thread and I don t know how to do this:
My code:
button1.setOnClickListener (new View.OnClickListener() {
#Override
public void onClick(View v) {
..........
button1.setEnabled(false);
button1.setVisibility(View.GONE);
button2.setVisibility(View.VISIBLE);
button2.setEnabled(true);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2800);
} catch (InterruptedException e) {
// ???????
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
button1.setEnabled(true);
button1.setVisibility(View.VISIBLE);
button2.setEnabled(false);
button2.setVisibility(View.GONE);
}
});
}
}).start();
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
..............
// Thread.interrupted(); -> does not work
}
});
} });
How can I make button2 listener to interrupt the thread?
class TestInterruptingThread1 extends Thread{
public void run(){
try{
Thread.sleep(1000);
System.out.println("task");
}catch(InterruptedException e){
throw new RuntimeException("Thread interrupted..."+e);
}
}
b2 //
{
try{
t1.interrupt(); // t1 is the thread to be interrupted
}catch(Exception e){System.out.println("Exception handled "+e);}
}
}
Instead of an anonymous implementation of the thread, make the thread a class variable. Suppose the name of the thread is btnOneThread
private Thread btnOneThread;
Initialize the thread where needed and start it.
btnOneThread = new Thread( ){...}
btnOneThread.start();
When the button2 is clicked call
if (btnOneThread != null) {
btnOneThread.interrupt();
}
By calling the thread.interrupt() method. You also need to save your Thread instance in a field of your class.
Thread t = new Thread() {...}
t.start();
and in the listener:
t.interrupt();
As to
// Thread.interrupted(); -> does not work
it will work from within a class derived from Thread and will be the same as this.interrupted(); t.interrupted() will work outside of the class definition.
Also note that the method isInterrupted() does not clear the interruption flag, while interrupted() has the side-effect of clearing the flag.
I have a simple question, how can I stop timer?
Button bCancel = (Button)findViewById(R.id.bt1);
bCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
finish();
startActivity(new Intent("com.jom.testcdt2.CANCELCLASS"));
}
});
final Thread logoTimer = new Thread(){
public void run(){
try {
int logoTimer = 0;
while (logoTimer < 10000) {
sleep(100);
logoTimer = logoTimer + 100;
}
startActivity(new Intent("com.jom.testcdt2.CLEARSCREEN"));
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
finally{
finish();
}
}
};
logoTimer.start();
}
When I press button bCancel, it starts a new activity, but timer is still running and after 10 seconds it starts CLEARSCREEN. On click I want timer to stop. How can I do that?
I would recommend using a CountDownTimer:
final CountDownTimer myTimer = new CountDownTimer(10000, 5000) {
#Override
public void onFinish() {
//DO SOMETHING AFTER 10 000 ms
}
#Override
public void onTick(long millisUntilFinished) {
//DO SOMETHING EVERY 5 000 ms until stopped
}
}
myTimer.start() //Starts it
myTimer.cancel() //Stops it
And instead of writing
(new Intent("com.jom.testcdt2.CANCELCLASS")
you should use
(new Intent(YOURCLASS.this, CancelClass.class)
Could you try to have a boolean value that you check in the while loop, and set it to true when you press the cancel button?
boolean pressedCancel = false;
....
while (logoTimer < 10000 && !pressedCancel) {
....