Reputation: 45921
I'm developing an Android 2.3.3 application and I need to run a method every X seconds.
In iOS, I have NSTimer, but in Android I don't know what to use.
Someone have recommend me Handler; another recommend me AlarmManager but I don't know which method fits better with NSTimer.
This is the code I want to implement in Android:
timer2 = [
NSTimer scheduledTimerWithTimeInterval:(1.0f/20.0f)
target:self
selector:@selector(loopTask)
userInfo:nil
repeats:YES
];
timer1 = [
NSTimer scheduledTimerWithTimeInterval:(1.0f/4.0f)
target:self
selector:@selector(isFree)
userInfo:nil
repeats:YES
];
I need something what works like NSTimer.
What do you recommend me?
Upvotes: 167
Views: 234659
Reputation: 3989
With Kotlin, we can now make a generic function for this!
fun repeatDelayed(delay: Long, action: () -> Unit): Handler {
val handler = Handler(Looper.getMainLooper())
handler.postDelayed(object : Runnable {
override fun run() {
action()
handler.postDelayed(this, delay)
}
}, delay)
return handler
}
And to use, just do:
val delay = 1000L
repeatDelayed(delay) {
myRepeatedFunction()
}
To cancel the repeating function:
val myHandler = repeatDelayed(1000L) {
myRepeatedFunction()
}
myHandler.removeCallbacksAndMessages(null)
Remember to cancel any ongoing Runnables that aren't relevant when the app isn't visible (such as periodic UI updates) in onStop:
override fun onStop() {
myHandler.removeCallbacksAndMessages(null)
}
Upvotes: 15
Reputation: 2990
I do it this way and it works fine (the code is written in Kotlin):
private lateinit var runnable: Runnable
private var handler = Handler(Looper.getMainLooper())
private val repeatPeriod: Long = 10000
Then reinit the runnable from inside your function
runnable = Runnable {
// Your code goes here
handler.postDelayed(runnable, repeatPeriod)
}
handler.postDelayed(runnable, repeatPeriod)
Note that if you don't postDelay twice the handler, the loop is not going to be intinity!
Upvotes: 2
Reputation: 284
In Kotlin, you can do it this way with a Runnable:
private lateinit var runnable: Runnable
private var handler = Handler(Looper.getMainLooper())
private val interval: Long = 1000
private var isRunning = false
val runnable = object : Runnable {
override fun run() {
// Do something every second
function()
// Call your runnable again after interval
handler?.postDelayed(runnable(this, interval))
}
}
// Call your function once
if (!isRunning) {
handler?.postDelayed(runnable, interval)
isRunning = true
}
// Remove your repeatedly called function
if (isRunning) {
handler?.removeCallbacks(runnable)
isRunning = false
}
Upvotes: 1
Reputation: 8325
The solution you will use really depends on how long you need to wait between each execution of your function.
If you are waiting for longer than 10 minutes, I would suggest using AlarmManager
.
// Some time when you want to run
Date when = new Date(System.currentTimeMillis());
try {
Intent someIntent = new Intent(someContext, MyReceiver.class); // intent to be launched
// Note: this could be getActivity if you want to launch an activity
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
0, // id (optional)
someIntent, // intent to launch
PendingIntent.FLAG_CANCEL_CURRENT // PendingIntent flag
);
AlarmManager alarms = (AlarmManager) context.getSystemService(
Context.ALARM_SERVICE
);
alarms.setRepeating(
AlarmManager.RTC_WAKEUP,
when.getTime(),
AlarmManager.INTERVAL_FIFTEEN_MINUTES,
pendingIntent
);
} catch(Exception e) {
e.printStackTrace();
}
Once you have broadcasted the above Intent
, you can receive your Intent
by implementing a BroadcastReceiver
. Note that this will need to be registered either in your application manifest or via the context.registerReceiver(receiver, intentFilter);
method. For more information on BroadcastReceiver
's please refer to the official documentation..
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent)
{
System.out.println("MyReceiver: here!") // Do your work here
}
}
If you are waiting for shorter than 10 minutes then I would suggest using a Handler
.
final Handler handler = new Handler();
final int delay = 1000; // 1000 milliseconds == 1 second
handler.postDelayed(new Runnable() {
public void run() {
System.out.println("myHandler: here!"); // Do your work here
handler.postDelayed(this, delay);
}
}, delay);
Upvotes: 203
Reputation: 4258
You can please try this code to call the handler every 15 seconds via onResume() and stop it when the activity is not visible, via onPause().
Handler handler = new Handler();
Runnable runnable;
int delay = 15*1000; //Delay for 15 seconds. One second = 1000 milliseconds.
@Override
protected void onResume() {
//start handler as activity become visible
handler.postDelayed( runnable = new Runnable() {
public void run() {
//do something
handler.postDelayed(runnable, delay);
}
}, delay);
super.onResume();
}
// If onPause() is not included the threads will double up when you
// reload the activity
@Override
protected void onPause() {
handler.removeCallbacks(runnable); //stop handler when activity not visible
super.onPause();
}
Upvotes: 96
Reputation: 40416
Use Timer for every second...
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
//your method
}
}, 0, 1000);//put here time 1000 milliseconds=1 second
Upvotes: 136
Reputation: 198
new CountDownTimer(120000, 1000) {
public void onTick(long millisUntilFinished) {
txtcounter.setText(" " + millisUntilFinished / 1000);
}
public void onFinish() {
txtcounter.setText(" TimeOut ");
Main2Activity.ShowPayment = false;
EventBus.getDefault().post("go-main");
}
}.start();
Upvotes: 6
Reputation: 6605
Here I used a thread in onCreate() an Activity repeatly, timer does not allow everything in some cases Thread is the solution
Thread t = new Thread() {
@Override
public void run() {
while (!isInterrupted()) {
try {
Thread.sleep(10000); //1000ms = 1 sec
runOnUiThread(new Runnable() {
@Override
public void run() {
SharedPreferences mPrefs = getSharedPreferences("sam", MODE_PRIVATE);
Gson gson = new Gson();
String json = mPrefs.getString("chat_list", "");
GelenMesajlar model = gson.fromJson(json, GelenMesajlar.class);
String sam = "";
ChatAdapter adapter = new ChatAdapter(Chat.this, model.getData());
listview.setAdapter(adapter);
// listview.setStackFromBottom(true);
// Util.showMessage(Chat.this,"Merhabalar");
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
In case it needed it can be stoped by
@Override
protected void onDestroy() {
super.onDestroy();
Thread.interrupted();
//t.interrupted();
}
Upvotes: 2
Reputation: 455
If you are familiar with RxJava, you can use Observable.interval(), which is pretty neat.
Observable.interval(60, TimeUnits.SECONDS)
.flatMap(new Function<Long, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull Long aLong) throws Exception {
return getDataObservable(); //Where you pull your data
}
});
The downside of this is that you have to architect polling your data in a different way. However, there are a lot of benefits to the Reactive Programming way:
With RxAndroid, you can handle threads in just 2 lines of code.
Observable.interval(60, TimeUnits.SECONDS)
.flatMap(...) // polling data code
.subscribeOn(Schedulers.newThread()) // poll data on a background thread
.observeOn(AndroidSchedulers.mainThread()) // populate UI on main thread
.subscribe(...); // your UI code
Please check out RxJava. It has a high learning curve but it will make handling asynchronous calls in Android so much easier and cleaner.
Upvotes: 20