如何解决检测当前忙碌日历事件的代码不支持重复事件的问题?
Great question! The problem with your current code is that recurring events are stored as templates in the CalendarContract.Events table. Their DTSTART and DTEND values only represent the first occurrence of the event, not every repeated instance. This means your query won't catch ongoing recurring events that started before the initial template's end time.
To fix this, you need to query the CalendarContract.Instances table instead. This system-managed table generates and stores all actual occurrences of recurring events (including modified exceptions to the recurrence rule), making it perfect for checking if you're currently in a busy event.
Step-by-Step Solution
1. Use the Instances Content URI
Replace CalendarContract.Events.CONTENT_URI with CalendarContract.Instances.CONTENT_URI. This URI requires a time range parameter to limit the instances you're querying (we'll set this to just the current moment to keep it efficient).
2. Adjust Projection and Selection
The Instances table uses INSTANCE_START and INSTANCE_END to represent the start/end time of each actual occurrence, instead of the template-focused DTSTART/DTEND from the Events table. The AVAILABILITY field is still available here to filter for busy events.
3. Updated Working Code
Here's the modified code that works for both one-time and recurring events:
// Required permission: android.permission.READ_CALENDAR long currentTime = System.currentTimeMillis(); // Define the time range (we only need instances covering the current moment) long queryStart = currentTime; long queryEnd = currentTime; String[] projection = new String[] { CalendarContract.Instances._ID }; String selection = CalendarContract.Instances.AVAILABILITY + " = ?"; String[] selectionArgs = new String[] { String.valueOf(CalendarContract.Events.AVAILABILITY_BUSY) }; // Query the Instances table with the mandatory time range parameters Cursor cur = ctx.getContentResolver().query( CalendarContract.Instances.CONTENT_URI.buildUpon() .appendQueryParameter(CalendarContract.Instances.BEGIN, String.valueOf(queryStart)) .appendQueryParameter(CalendarContract.Instances.END, String.valueOf(queryEnd)) .build(), projection, selection, selectionArgs, null ); // Check if any busy events are currently active boolean isCurrentlyBusy = cur != null && cur.getCount() > 0; // Always remember to close the cursor to avoid resource leaks! if (cur != null) { cur.close(); }
Key Notes
- Permissions: Ensure your app has the
READ_CALENDARpermission (declare it in your manifest and request runtime permission for Android 6.0+). - API Compatibility: The
Instancestable is available starting from API Level 14 (Android 4.0), which covers nearly all modern Android devices. - Exception Handling: This query automatically accounts for modified recurring event instances (like a single occurrence that was rescheduled or deleted), since the
Instancestable reflects these real-time changes.
内容的提问来源于stack exchange,提问作者Felix

