【问题标题】:How to avoid duplication of events in Android Calendar?如何避免 Android 日历中的事件重复?
【发布时间】:2017-03-28 02:15:56
【问题描述】:

我通过 API 调用从服务器获取(一周的)事件列表,我的应用需要将它们同步到设备中的日历。可以在服务器上更新或删除事件,而无需来自应用程序的任何交互。而且我需要在每次刷新屏幕时将它们同步到日历。

为了使我的日历上的活动与我的服务器保持同步,我在刷新时执行了以下操作:

  1. 从日历中删除给定一周的所有事件。
  2. 然后插入我从服务器获取的事件。

    public static void deleteAllEventsInWeekOfCalendar(Activity activity, int calId, long weekStartTimeMillis, long weekEndTimeMillis) {
        try {
        Uri eventUri = Uri.parse("content://com.android.calendar/events");
        String[] projection = new String[]{Events._ID, Events.TITLE, Events.DTSTART, Events.DESCRIPTION};
        String whereClause = Events.CALENDAR_ID + "=" + calId +
                " AND " + Events.DTSTART + " >= " + weekStartTimeMillis +
                " AND " + Events.DTSTART + " <= " + weekEndTimeMillis +
                " AND " + Events.DESCRIPTION + " LIKE '% Added by MyApp'";
    
        Cursor cursor = activity.getContentResolver().query(eventUri, projection, whereClause, null, Events.DTSTART);
        if (cursor != null && cursor.moveToFirst()) {
            Log.v("HowMany", cursor.getCount() + " matching events Found");
            int numOfDeleted = 0;
            do {
                try {
                    String event_id = cursor.getString(cursor.getColumnIndexOrThrow(projection[0]));
                    int numOfRowsDeleted = activity.getContentResolver().delete(ContentUris.withAppendedId(eventUri, Long.parseLong(event_id)), null, null);
                    if (numOfRowsDeleted == 1) {
                        ++numOfDeleted;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } while (cursor.moveToNext());
            cursor.close();
            Log.v("HowMany", numOfDeleted + " deleted");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    }
    

这是我将所有事件插入日历的代码:

 public static void doAddCalendarEvent(MyEvent myEvent, Activity activity, int calendarId) {
    try {
        if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        String desc = myEvent.getDesc();
        desc += "\n\n Added by MyApp";

        ContentResolver cr = activity.getContentResolver();
        ContentValues values = new ContentValues();
        values.put(Events.DTSTART, myEvent.getEventStartTime());
        values.put(Events.DTEND, myEvent.getEventEndTime());
        values.put(Events.TITLE, myEvent.getTitle());
        values.put(Events.DESCRIPTION, desc);
        values.put(Events.CALENDAR_ID, calendarId);
        values.put(Events.EVENT_LOCATION, myEvent.getLocation());
        values.put(Events.STATUS, Events.STATUS_CONFIRMED);
        values.put(Events.AVAILABILITY, Events.AVAILABILITY_BUSY);
        if (hasAlarm) {
            values.put(Events.HAS_ALARM, true);
        }
        values.put(Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());
        long eventId = 0;
        Uri uri = cr.insert(Events.CONTENT_URI, values);
        if (uri != null) {
            eventId = Long.parseLong(uri.getLastPathSegment());
            Log.v(TAG, "INSERTED EVENT ID=>" + eventId + "--->" + startDate);
        }
        if (hasAlarm) {
            setReminder(cr, reminderValue, eventId);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

问题:有时事件在日历上重复。如何避免重复?我哪里错了?请建议。

【问题讨论】:

    标签: android android-calendar android-contentresolver


    【解决方案1】:

    我假设您正在使用同步适配器与日历接口。

    同步适配器有两个重要的方法:

    onPerformSync(...),和 onSyncCanceled(...)

    每当您拨打ContentResolver.requestSync 或自动同步设置为true 时,都会调用onPerformSync

    在执行时,onPerformSync 可以被 Android 中断。如果设备资源不足或您的应用不再处于前台,则可能会发生这种情况。

    当中断时,同步适配器将停止执行并调用onSyncCanceled。 Sync Adapter 的默认行为是在第一时间重试失败的同步消息。因此,如果您的应用设法再次抢占操作系统资源,它将重播中断的同步消息。

    您的某些消息可能正在被完全处理,而在onPerformSync 即将完成之前,同步适配器被中断。此时您设法保存了事件,但是,同步适配器认为同步失败,因此将在下次尝试同步时再次重播相同的消息。

    我不确定您是否一次同步一个事件,因此我无法提供明确的解决方案。但是,您可以做的是更改同步适配器的默认行为以阻止它重播“失败”消息。

    Bundle extras = new Bundle(); ... extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); CalendarConstants.AUTHORITY, true); ContentResolver.requestSync(mAccount, CalendarConstants.AUTHORITY, extras);

    OnSyncCanceled 中,您可以进行一些简单的检查以确保消息成功,即出现在日历的事件表中。如果没有,则手动重播。如果存在,则 SyncAdapter 将简单地转到下一条消息,并且您不会收到任何重复消息。

    或者,您可以确保onPerformSync 中的所有操作都是原子的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-23
      • 2018-05-03
      相关资源
      最近更新 更多