On Android it is more complex - you need a Timer and TimerTask, and then you need another Runnable to give to Activity.runOnUiThread(..), and then your actual method. It all adds a lot of code bloat, especially if you have a few activities in your app. AsyncTask is good for updating the UI while a background process is running, but for just a simple update interval it's no use.
This is a reasonably simple solution to the problem - the MyTimer class has a setInterval method that behaves similarly to Javascript. The usage is:
- Set the timer:
int timer=MyTimer.setInterval(this, "updateUI", 2000,true);
(where "updateUI" is a method with the signature: public void updateUI() {..})
- Cancel the timer:
timer=MyTimer.cancelTimer(timer);
- The cancel operation returns -1 if the cancel was performed successfully, so you can just test if the timer ==-1 to tell if you need to start it again.
- The code above is called from the activity, the first argument of setInterval should be an Activity object.
- There is a static debug variable if it doesnt work as expected (MyTimer.debug=true).
- If there is an exception in the target method -> the timer is cancelled.
- MAKE SURE YOU CANCEL THE TIMER (in onStop or onPause). If the timer is not cancelled, then it will prevent garbage collection, a possible way around is just to return the Timer object instead of holding it in a Vector.
- Note that this type of usage can potentially use a lot of battery if its just left running, the updateUI method (or whatever the method name is), should do the minimum processing necessary. It should just update a couple of UI elements or something - not do masses of calculations (store results as variables is a simple solution).
package co.uk.sentinelweb.util; /* * licensed under CC BY-SA : http://creativecommons.org/licenses/by-sa/3.0/legalcode */ import java.lang.reflect.Method; import java.util.Timer; import java.util.TimerTask; import java.util.Vector; import android.app.Activity; import android.util.Log; public class MyTimer { public static VectorCAVEAT: While I haven't found anything in the API to do this (easily), it is possible that it is in there somewhere. If it is then let me know, and I'll update this.timers = new Vector (); public static boolean debug = false;// turn on to check timer activates and cancels public static int setInterval(Activity object,String method,int interval,boolean isUI) { Timer timeoutTimer= new Timer(); TimeoutTask timeoutTimerTask; try { timeoutTimerTask = new TimeoutTask(object,method,isUI,timeoutTimer.hashCode()); if (debug) {Log.d(MyTimer.class.getSimpleName(), "timer created :");} } catch (Exception e) { Log.d(MyTimer.class.getSimpleName(), "error creating timer :"+method,e); return -1; } timeoutTimer.scheduleAtFixedRate(timeoutTimerTask, 0, interval); timers.add(timeoutTimer); return timeoutTimer.hashCode(); } public static int cancelTimer(int code) { Timer timeoutTimer = null; for (int i=0;i<timers.size();i++) { if (timers.get(i).hashCode()==code) { timeoutTimer=timers.get(i); } } if (timeoutTimer!=null) { timers.remove(timeoutTimer); timeoutTimer.cancel(); timeoutTimer.purge(); if (debug) {Log.d(MyTimer.class.getSimpleName(), "timer deleted :");} return -1; } else { if (debug) {Log.d(MyTimer.class.getSimpleName(), "timer not found :"+code);} } return code; } private static class TimeoutTask extends TimerTask { Activity targetObject; Method targetMethod; Runnable invoker; int code ; public TimeoutTask(Activity targetObject, String targetMethod,boolean isUI,int code) throws SecurityException, NoSuchMethodException { super(); this.targetObject = targetObject; this.targetMethod = targetObject.getClass().getDeclaredMethod(targetMethod, new Class[]{}); this.code=code; if (isUI) { invoker = new ThreadRunner(this.targetObject,this.targetMethod); } } @Override public void run() { try { if (debug) {Log.d(MyTimer.class.getSimpleName(), "invoke timer :");} if (invoker==null) { targetMethod.invoke(targetObject, new Object[]{}); } else { targetObject.runOnUiThread(invoker); } } catch(Exception e) { Log.d(MyTimer.class.getSimpleName(), "error invoking:"+targetMethod.getName(),e); cancelTimer(code); Log.d(MyTimer.class.getSimpleName(), "timer:"+code+" has been cancelled"); } } } private static class ThreadRunner implements Runnable{ Activity targetObject; Method targetMethod; public ThreadRunner(Activity targetObject, Method targetMethod) { super(); this.targetObject = targetObject; this.targetMethod = targetMethod; } @Override public void run() { try { targetMethod.invoke(targetObject, new Object[]{}); } catch (Exception e) { Log.d(MyTimer.class.getSimpleName(), "error invoking:"+targetMethod.getName(),e); } } } }
This code is made open under the CC BY-SA licence.