I am trying to call my takepicture() method after every 1 minute. So, I tried using the handler class and then tried calling my method within its run function. However, when I tried doing a step wise debugging, it never enters the run method at all. Can anyone please suggest me what I am doing wrong? I am trying to call it from my fragment.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");
final Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
Log.d("HandlerThread","This is from the HandlerThread");
takePicture();
handler.postDelayed(this, 60000);
}
};
}
Try this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
Log.d("HandlerThread","This is from the HandlerThread");
takePicture();
}
}, 60000);
}
Rather than defining the handler.postDelayed within run method.I have just changed the call within your main thread itself.
Kindly mark it as answer if it solves your problem.
You never call any method that would run the Runnable. You only specified its behavior inside the run() function.
In order to start the Runnable, call something like handler.postDelayed(r, 0);
Just an info: please note that your Handler is still tied to the main Thread. See this answer and this one if you want to run it on a separate thread.
You should make an initial call to start the handler functionality.
ie , handler.post(r);
Related
Here is my code:
public class MainActivity extends AppCompatActivity {
Runnable runnable;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
runnable=new Runnable() {
#Override
public void run() {
Log.i("hello","runnable") ;
}
};
}
}
Why is it not printing log? Do I need a handler and then pass runnable object in it? Does run() method runs only once?
Currently you just define your runnable, but it will be never called. There are some ways how you can use a runnable e.g. in a thread or also in a Handler.
Here is an example for a Thread where you cannot update the UI:
new Thread(runnable).start();
If you need to update the UI you should use a Handler like this:
new Handler().post(runnable); // do as soon as possible
new Handler().postDelayed(runnable, 300); // do it after 300ms
Normally it doesn't make sense but you can use your runnable also as a kind of callback like this:
runnable.run();
A runnable can been used multiple times by using that three examples above multiple times.
I want to set dynamically auto scroll speed to WebView. In onCreate calling autoScroll(25) and remove it, nextly calling autoScroll(300) but when the apk is running the auto scroll speed is 25 so earlier called 'mHandler.postDelayed' do not removing. How to fix the problem?
Handler mHandler;
Runnable runnable;
WebView wv;
protected void onCreate(Bundle savedInstanceState) {
...
autoScroll(25);
mHandler.removeCallbacks(runnable);
autoScroll(300);
}
public void autoScroll(final int speed){
if(mHandler == null) {
mHandler = new Handler();
}
wv.post(runnable = new Runnable() {
#Override
public void run() {
wv.scrollBy(0, 1);
mHandler.postDelayed(this, speed);
}
});
}
mHandler.removeCallbacks(runnable);
will only remove any pending posts of Runnable r that are in the message queue. It will not stop an already running thread. You have to explicitly stop the thread. One way to stop that thread is to use a boolean variable as a flag and run your code inside runnable based on the value of that flag. You can take some hints from https://stackoverflow.com/a/5844433/1320616
I'm trying to build an Android app which will repeatedly run some process every 10 mins.
As I found out Handlers are more reliable than timers or scheduling. So I'm going to develop my app using the Handlers using the given below codes.
I'm little bit concerned that the below codes will create separate Handlers at each time I start the app and keep them running parallel, may be since I'm creating the Handler on onCreate.
So what is the best way to keep only a single Handler runs in background at a time?
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler(); // new handler
handler.postDelayed(runnable, 1000*60*10); // 10 mins int.
setContentView(R.layout.activity_pro__sms);
}
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* my set of codes for repeated work */
foobar();
handler.postDelayed(this, 1000*60*10); // reschedule the handler
}
};
You can extend Application class and do your work in it.
public class App extends Application {
private Handler handler;
#Override
protected void onCreate() {
super.onCreate();
handler = new Handler(); // new handler
handler.postDelayed(runnable, 1000*60*10); // 10 mins int.
setContentView(R.layout.activity_pro__sms);
}
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* my set of codes for repeated work */
foobar();
handler.postDelayed(this, 1000*60*10); // reschedule the handler
}
};
}
And declare your class in manifest:
<application android:name=".App">
Edited
But it will work only if your app is running, otherwise you can use AlarmManager.
I decided to answer my own question since I've found out how to do it right way. The Android way. First of all what I was trying to do and posted in the question is a wrong approach to my requirement. Now I'm posting this so someone else will not do it wrong way but the following way.
Android has few options for timing.
Timer-task -> runs while application is alive. best for short term timing. Resource usage is higher.
Handler -> runs while application is alive. But not suitable to used as a scheduler. (this is what I've asked and it's not the correct way to do that). Handlers are the best way to do something repeatedly till the app is killed.
Alarm-manager -> The best way to schedule something to happen in future even if the app is killed. (this is what I should apply for my app).
This is what I figured out. Correct me if I'm wrong.
first define an utility class
public abstract class HandlerPeriodRunnable implements Runnable {
private Handler periodHandler;
private int msPeriod;
public HandlerPeriodRunnable(Handler periodHandler, int msPeriod) {
this.periodHandler = periodHandler;
this.msPeriod = msPeriod;
}
#Override
public void run() {
periodRun();
if (msPeriod > 0) {
periodHandler.postDelayed(this, msPeriod);
}
}
abstract public void periodRun();
}
then use it
final Handler mUIHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mUIHandler.postDelayed(new HandlerPeriodRunnable(mUIHandler, 1000) {
#Override
public void periodRun() {
}
}, 2000);
}
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.