I have a fragment where a timer starts running immediately when you initialize and it shows a different image every 6 seconds.
I haven't fully figured out how this timer thing works, but somehow i got it running and i understand the timer runs in a different thread... not even sure what exactly that means : )
But the timer causes a crash when i load a different fragment. so i guess i have to CANCEL the timer when the activity is closed?
That brings me to two questions.
1) Can i run myTimer.cancel from anywhere? if yes, how do i run it from my main activity or from other fragments.
2) is there something like onCloseActivity i can use for this fragment. so i can cancel my timer as soon as i leave the fragment?
this is how i start my timer:
// timer
Timer myTimer;
/////////////////////
/////// timer ///////
/////////////////////
private void runTimer() {
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
TimerMethod();
}
}, 5000, 5000);
}
private Runnable Timer_Tick = new Runnable() {
public void run() {
// next image if THIS one is loaded
nextImage();
}
};
private void TimerMethod() {
getActivity().runOnUiThread(Timer_Tick);
}
And here is my error:
getActivity().runOnUiThread(Timer_Tick);
causes the error when i load a different fragment.
E/AndroidRuntime: FATAL EXCEPTION: Timer-1
Process: com.murmurcalgary.murmurcalgaryevolvd, PID: 8668
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v4.app.FragmentActivity.runOnUiThread(java.lang.Runnable)' on a null object reference
at com.murmurcalgary.murmurevolvd.fragments.EventsFragment.TimerMethod(EventsFragment.java:92)
at com.murmurcalgary.murmurevolvd.fragments.EventsFragment.access$000(EventsFragment.java:45)
at com.murmurcalgary.murmurevolvd.fragments.EventsFragment$1.run(EventsFragment.java:77)
at java.util.Timer$TimerImpl.run(Timer.java:284)
You can use fragment's life-cycle methods for stopping the timer.
Override onStop() method in fragment and then cancel the timer task inside that method.
#Override
public void onStop() {
super.onStop();
if(timerTask != null){
timerTask.cancel();
//cancel timer task and assign null
}
}
Related
Hello i am new in android, i have a problem when i develop my application.
I have a modal with timer and close button. When the timer is over , the modal will close, or close the modal before the timer is over with close button. Here the picture :
But the problem when i close the modal manually with press the close button, the method that run timer is still running and tried to close the modal although the modal is already closed , this is caused my application crashed. The error is
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String android.content.Context.getPackageName()' on a null
object reference
How can i stop the method when i press close button?
Here my timer method to close modal when the timer is over :
public void startTimer(){
int hoursToGo = 0;
int minutesToGo = 0;
int secondsToGo = 10;
int millisToGo = secondsToGo*1000+minutesToGo*1000*60+hoursToGo*1000*60*60;
new CountDownTimer(millisToGo,1000) {
#Override
public void onTick(long millis) {
int seconds = (int) (millis / 1000) % 60 ;
int minutes = (int) ((millis / (1000*60)) % 60);
String text = String.format("%02d:%02d",minutes,seconds);
tv.setText(text);
}
#Override
public void onFinish() {
tv.setText("Request Timeout");
}
}.start();
final AlertDialog d = (AlertDialog) getDialog();
final Timer timer2 = new Timer();
timer2.schedule(new TimerTask() {
public void run() {
d.dismiss();
timer2.cancel(); //this will cancel the timer of the system
Intent i = new Intent(getActivity(), PromoActivity.class);
i.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
getActivity().startActivityForResult(i,0);
}
}, 10000);
}
i execute the method in here :
public void onResume(){
super.onResume();
startTimer();
}
You have to call timer2.cancel(); when you press the close button
Try below steps :
Assign the CountDownTimer instance to a variable, e.g.
CountDownTimer cdt = new CountDownTimer(millisToGo,1000)
...then when you want to stop it, call
cdt.cancel()
Not sure why you need another Timer instance, you should remove it and put that code in
CountDownTimer onFinish()
Keep a reference on your TimerTask and call myTimerTask.cancel() on it.
Please use following instead of getActivity() for the NullPointerException you are getting i.e.
Create a class variable context and give it's value in onCreateView() of your fragment i.e.
Context context; //class variable
context = getActivity(); //inside onCreateView()
Intent i = new Intent(context, PromoActivity.class);
I am using java and android studio. I am trying to close an activity I set up with a scheduleatfixedrate when I pause or destroy the app. The problem is I cannot get the code to resolve the timer and tasknew reference I use to set up the scheduleatrfixedrate in the onpause and onDestroy methods. Below is my code:
#Override
protected void onResume() {
super.onResume();
TimerTask tasknew = new readDevice();
Timer timer = new Timer();
timer.scheduleAtFixedRate(tasknew, 1000, 500);
}
// Activity paused
#Override
protected void onPause() {
super.onPause();
tasknew.cancel();
timer.purge();
}
Without being able to cancel the timer, it just keeps running in the background.
Update:
I solved the problem which I update my solution in case someone else new to java has this problem. I found out all I had to do is move the statement creating tasknew and timer outside of onResume and moved the cancel and purge to the onDestroy method. Below is my working code.
public class DeviceControlActivity extends Activity {
private TimerTask tasknew = new readDevice();
private Timer timer = new Timer();
#Override
protected void onResume() {
super.onResume();
timer.scheduleAtFixedRate(tasknew, 1000, 500);
}
#Override
protected void onDestroy() {
super.onDestroy();
tasknew.cancel();
timer.purge();
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
}
I guess it would have been enough to create a daemon Timer:
new Timer(true)
So, the timer would end when the rest of non-daemon threads of the program end.
In my onCreate method in my activity i call a method from an object and pass the methods value as 1 which means to start a timer in the objects class. However I want to stop the timer whenever the app closes, loses focus or someone pressed the back button on their device and exited the app. I tried doing this below my onCreate method with an onPause, onStop, onDestroy and entered the methods value as 2 for the object which means to cancel the timer. However my problem is that whenever someone presses the back button on their device and then goes back in to the app the same timer is running twice because the app did not cancel the timer in the onStop, onPause or onDestroy. Why didn't the onStop, onPause and onDestroy stop the timer and how do i make it stop the timer so two arent running when the app is reopened?
Activity below
Ship mShip = new Ship(0,0,0);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
mShip.timerStart(1);
}
#Override
public void onPause()
{
super.onPause();
mShip.timerStart(2);
}
#Override
public void onStop()
{
super.onStop();
mShip.timerStart(2);
}
#Override
public void onDestroy()
{
super.onDestroy();
mShip.timerStart(2);
}
Ship Class below
public static int counter = 0;
public static int counterPerSec = 5;
TimerClass startTimer = (TimerClass) new TimerClass(2000,1000)
{
#Override
public void onFinish() {
counter += counterPerSec;
this.start();
}
};
public void timerStart(int x) {
if(x == 1)
{
startTimer.start();
}
if(x == 2)
{
startTimer.cancel();
}
}
Timer Class
public class TimerClass extends CountDownTimer {
public TimerClass(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override // when timer is finished
public void onFinish() {
this.start();
}
#Override // on every tick of the timer
public void onTick(long millisUntilFinished) {
}
}
I can not see, why your timer is not canceled. But there is another bug in your code: You can not pause and resume a countdown timer by calling resume and start.
If your time gets canceled, you should save the old timer vaules. And if your timer has to be resumed, you can create a new timer with the old timer values. See: Android: How to pause and resume a Count Down Timer?
To your question: Can you debug and check if onPause, onStop, onDestroy is called? Is there any exception thrown? Do you have any compile warnings?
Last important question: How do you know that two timers are running?
Well, I think I can correctly assume that onPause, onStop, and onDestroy are executing, so I would venture to guess that there is a bug in your TimerClass class.
I recently began working with Java and am exploring Android development. I was trying to port over one of the Java programs I made, but I am having some difficulty with getting the java Timer to function the same way in Android. I read through a number of posts and they, for the most part, indicated that it would be better to use the Handler class in android as opposed to Timer.
This was my timer in Java:
playTimer = new Timer(1000/model.getFPS(), new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// do something
...
if( finished everything ) playTimer.stop();
}
});
And once a certain button was clicked, I would simply run "playTimer.start()" to start it.
As you can see, I had it set up so that the user could set the FPS they wanted (by simply setting the first parameter of the Timer class to 1000/model.getFPS()).
Now I've tried to do something similar in Android using handlers, but I am having some difficulty. It appears that the Handler ticks are not firing at the proper intervals. It seems that they are quite slow compared to what I need it to be. This is what I did in android so far:
public void startTimer() {
playHandler = new Handler();
startTime = System.currentTimeMillis();
playHandler.removeCallbacks(updateTimeTask);
playHandler.postDelayed(updateTimeTask, 0);
}
private Runnable updateTimeTask = new Runnable() {
public void run() {
// do something
...
if( finished everything ) playHander.cancel();
else {
playHandler.postDelayed(updateTimeTask, 1000/model.getFPS());
}
}
};
Excuse the semi-pseudocode. Can anyone shed any light? Thanks guys.
You can use a timer as below. The timer runs every second incrementing the counter. Displs the counter value in textview.
Timer runs on a different thread. SO you should set the text on the UI Thread.
The counter runs from 0 to 99. After 99 the timer is cancelled. Also cancel the timer when not required like in onPause().
public class MainActivity extends Activity {
TextView _tv,tv2;
Timer _t;
int _count=0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_tv = (TextView) findViewById( R.id.textView1 );
_t = new Timer();
_tv.setText(R.string.app_name);
_t.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
_count++;
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
_tv.setText(""+_count);
if(_count==99)
{
_t.cancel();
}
}
});
}
}, 1000, 1000 ); //change this value of 1000 to whatever you need.
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
_t.cancel();
}
}
If you decide not to use Timer (for whatever reason) you can just write a separate Thread that sleeps for x milliseconds and then wakes up and calls whatever Runnable you want it to call. That's going to be pretty precise. I have it working at the 10 millisecond level and it works quite nicely.
Just remember that it HAS to call a Runnable because a separate Thread can't have direct effect on anything on the main display thread.
public boolean keepPlayingAnimation = true
Handler h = new Handler()
Runnable updateDisplay = new Runnable(){
public void run(){
//do something in my display;
}
}
new Thread(){
public void run(){
while(keepPlayingAnimation){
try{
sleep(10);
}catch(Exception e){
}
h.post(updateDisplay);
}
}
}.start();
Just don't forget to set keepPlayingAnimation to false when you're done with this cause otherwise it will sit there running in the background for ever (or just about).
Take a look at Android Timer
It already has everything you need i guess. From ticking every 1 second to finish handly and so on.
Here is an example how to setup an TimerTask: setup
Not sure if you need such but i just remembered that i made this.
I want to send a notification after 5 seconds.
I found this code example to do something after 5 seconds, but I just can set a Log.e().
The Notification method is also working. But if I want to call the method setNotification(), I get a RuntimeError after 5 seconds:
Can't create Handler inside Thread that has not called looper.prepare().
I found very much help, but nothing works. So I hope you can help me.
public class Reminder {
Timer timer;
public Reminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(), seconds * 1000);
}
}
class RemindTask extends TimerTask {
public void run() {
todo_list rem = new todo_list();
rem.setNotification("Todo!", false, 1);
}
}
public class todo_list extends ListActivity {
public void onCreate(Bundle savedInstanceState) {
new Reminder(5);
}
public void setNotification(String text, boolean ongoing, int id) {}
}
You need to call rem.setNotification from a thread which will keep running always. One way is to use runonuithread
runonUithread(new Runnable(){
run(){
rem.setNotification("Todo!",false,1);
}
});
You'll get this error when you execute some code that shouldn't be done in another thread than the UI thread. So simple get an activity object and call runOnUiThread(Runnable action) {} on it. Place that code that generates the error in the Runnable.
I hope this helps.