Asked  7 Months ago    Answers:  5   Viewed   34 times

What is the proper way to set a timer in android in order to kick off a task (a function that I create which does not change the UI)? Use this the Java way: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

Or there is a better way in android (android's handler)?

 Answers

47

Standard Java way to use timers via java.util.Timer and java.util.TimerTask works fine in Android, but you should be aware that this method creates a new thread.

You may consider using the very convenient Handler class (android.os.Handler) and send messages to the handler via sendMessageAtTime(android.os.Message, long) or sendMessageDelayed(android.os.Message, long). Once you receive a message, you can run desired tasks. Second option would be to create a Runnable object and schedule it via Handler's functions postAtTime(java.lang.Runnable, long) or postDelayed(java.lang.Runnable, long).

Tuesday, June 1, 2021
 
PeterTheLobster
answered 7 Months ago
23

So the first part of the answer is how to do what the subject asks as this was how I initially interpreted it and a few people seemed to find helpful. The question was since clarified and I've extended the answer to address that.

Setting a timer

First you need to create a Timer (I'm using the java.util version here):

import java.util.Timer;

..

Timer timer = new Timer();

To run the task once you would do:

timer.schedule(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);

To have the task repeat after the duration you would do:

timer.scheduleAtFixedRate(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000, 2*60*1000);

// Since Java-8
timer.scheduleAtFixedRate(() -> /* your database code here */, 2*60*1000, 2*60*1000);

Making a task timeout

To specifically do what the clarified question asks, that is attempting to perform a task for a given period of time, you could do the following:

ExecutorService service = Executors.newSingleThreadExecutor();

try {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            // Database task
        }
    };

    Future<?> f = service.submit(r);

    f.get(2, TimeUnit.MINUTES);     // attempt the task for two minutes
}
catch (final InterruptedException e) {
    // The thread was interrupted during sleep, wait or join
}
catch (final TimeoutException e) {
    // Took too long!
}
catch (final ExecutionException e) {
    // An exception from within the Runnable task
}
finally {
    service.shutdown();
}

This will execute normally with exceptions if the task completes within 2 minutes. If it runs longer than that, the TimeoutException will be throw.

One issue is that although you'll get a TimeoutException after the two minutes, the task will actually continue to run, although presumably a database or network connection will eventually time out and throw an exception in the thread. But be aware it could consume resources until that happens.

Tuesday, June 1, 2021
 
hnkk
answered 7 Months ago
46

Nope, it is more complicated than just calling a method, if you want to transparently add it into the user's calendar.

You've got a couple of choices;

  1. Calling the intent to add an event on the calendar
    This will pop up the Calendar application and let the user add the event. You can pass some parameters to prepopulate fields:

    Calendar cal = Calendar.getInstance();              
    Intent intent = new Intent(Intent.ACTION_EDIT);
    intent.setType("vnd.android.cursor.item/event");
    intent.putExtra("beginTime", cal.getTimeInMillis());
    intent.putExtra("allDay", false);
    intent.putExtra("rrule", "FREQ=DAILY");
    intent.putExtra("endTime", cal.getTimeInMillis()+60*60*1000);
    intent.putExtra("title", "A Test Event from android app");
    startActivity(intent);
    

    Or the more complicated one:

  2. Get a reference to the calendar with this method
    (It is highly recommended not to use this method, because it could break on newer Android versions):

    private String getCalendarUriBase(Activity act) {
    
        String calendarUriBase = null;
        Uri calendars = Uri.parse("content://calendar/calendars");
        Cursor managedCursor = null;
        try {
            managedCursor = act.managedQuery(calendars, null, null, null, null);
        } catch (Exception e) {
        }
        if (managedCursor != null) {
            calendarUriBase = "content://calendar/";
        } else {
            calendars = Uri.parse("content://com.android.calendar/calendars");
            try {
                managedCursor = act.managedQuery(calendars, null, null, null, null);
            } catch (Exception e) {
            }
            if (managedCursor != null) {
                calendarUriBase = "content://com.android.calendar/";
            }
        }
        return calendarUriBase;
    }
    

    and add an event and a reminder this way:

    // get calendar
    Calendar cal = Calendar.getInstance();     
    Uri EVENTS_URI = Uri.parse(getCalendarUriBase(this) + "events");
    ContentResolver cr = getContentResolver();
    
    // event insert
    ContentValues values = new ContentValues();
    values.put("calendar_id", 1);
    values.put("title", "Reminder Title");
    values.put("allDay", 0);
    values.put("dtstart", cal.getTimeInMillis() + 11*60*1000); // event starts at 11 minutes from now
    values.put("dtend", cal.getTimeInMillis()+60*60*1000); // ends 60 minutes from now
    values.put("description", "Reminder description");
    values.put("visibility", 0);
    values.put("hasAlarm", 1);
    Uri event = cr.insert(EVENTS_URI, values);
    
    // reminder insert
    Uri REMINDERS_URI = Uri.parse(getCalendarUriBase(this) + "reminders");
    values = new ContentValues();
    values.put( "event_id", Long.parseLong(event.getLastPathSegment()));
    values.put( "method", 1 );
    values.put( "minutes", 10 );
    cr.insert( REMINDERS_URI, values );
    

    You'll also need to add these permissions to your manifest for this method:

    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    

Update: ICS Issues

The above examples use the undocumented Calendar APIs, new public Calendar APIs have been released for ICS, so for this reason, to target new android versions you should use CalendarContract.

More infos about this can be found at this blog post.

Sunday, June 6, 2021
 
CMOS
answered 6 Months ago
54

Set your compileSdkVersion 'android-P' and targetSdkVersion 28

EDIT: Now compileSdkVersion 28 should also work meaning you no longer have to set it to android-P

Saturday, September 18, 2021
 
oroshnivskyy
answered 3 Months ago
70

Purely by guessing, I changed the following in my gradle config

from:

  testOptions {
    execution 'ANDROID_TEST_ORCHESTRATOR'
  }

to

  testOptions {
    execution 'ANDROIDX_TEST_ORCHESTRATOR'
  }

and all seems to work.

Sunday, September 19, 2021
 
Shevek
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share