DEV Community

HarmonyOS
HarmonyOS

Posted on

Calendar Event Deletion Performance Optimization

Read the original article:Calendar Event Deletion Performance Optimization

Context

In Calendar Kit, events belong to specific calendar accounts. One calendar account can have multiple events, but each event belongs to only one calendar. After obtaining a calendar account object, you can manage events under that account, including creation, deletion, modification, and querying operations.

When using Calendar Kit, you need to declare permissions in module.json5: ohos.permission.READ_CALENDAR and ohos.permission.WRITE_CALENDAR.

Description

The event deletion interfaces deleteEvent(), deleteevents(), and deleteCalendar() have significant time consumption differences. There are three ways to delete events:

  1. Single event deletion by ID: Use deleteEvent() interface for individual event deletion
  2. Batch deletion by IDs: Use deleteevents() interface for batch deletion of specified events
  3. Calendar account deletion: Use deleteCalendar() to delete the entire calendar account and all its events

Solution

Performance comparison for deleting 50 events:

  • deleteEvent: Single deletion ~38ms, 50 deletions ~935ms
  • deleteevents: 50 deletions ~852ms
  • deleteCalendar: Account deletion ~109ms

Choose the appropriate deletion method based on business requirements. Sample code demonstrates the implementation with timing measurements:

import { abilityAccessCtrl, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit';
import { calendarManager } from '@kit.CalendarKit';
import { BusinessError } from '@kit.BasicServicesKit';

let calendarMgr: calendarManager.CalendarManager | null = null;
let calendar1: calendarManager.Calendar | undefined = undefined;
let calendar2: calendarManager.Calendar | undefined = undefined;
let calendar3: calendarManager.Calendar | undefined = undefined;
const permissions: Permissions[] = ['ohos.permission.READ_CALENDAR', 'ohos.permission.WRITE_CALENDAR'];

// Chunk function implementation
function chunkArray(arr: calendarManager.Event[], chunkSize: number): calendarManager.Event[][] {
  const result: calendarManager.Event[][] = [];
  for (let i = 0; i < arr.length; i += chunkSize) {
    result.push(arr.slice(i, i + chunkSize));
  }
  return result;
}

@Entry
@Component
struct CalendarPage {
  @State message: string = 'Hello World';
  events: calendarManager.Event[] = [];
  calendarAccount1: calendarManager.CalendarAccount = {
    name: 'test1',
    type: calendarManager.CalendarType.LOCAL,
    displayName: 'MyCalendar1'
  };
  calendarAccount2: calendarManager.CalendarAccount = {
    name: 'test2',
    type: calendarManager.CalendarType.LOCAL,
    displayName: 'MyCalendar2'
  };
  calendarAccount3: calendarManager.CalendarAccount = {
    name: 'test3',
    type: calendarManager.CalendarType.LOCAL,
    displayName: 'MyCalendar3'
  };

  requestPermissions(permissions: Array<Permissions>) {
    let atManager = abilityAccessCtrl.createAtManager();
    const mContext = getContext(this) as common.UIAbilityContext;
    atManager.requestPermissionsFromUser(mContext, permissions).then((result: PermissionRequestResult) => {
      let grantStatus: Array<number> = result.authResults;
      let length: number = grantStatus.length;
      for (let i = 0; i < length; i++) {
        if (grantStatus[i] === 0) {
          // Already authorized, can continue with target operations
          calendarMgr = calendarManager.getCalendarManager(mContext);
        } else {
          // User denied authorization
          return;
        }
      }
    }).catch((error: BusinessError) => {
      console.error(`get Permission error, error. Code: ${error.code}, message: ${error.message}`);
    })
  }

  aboutToAppear(): void {
    // Request calendar read/write permissions
    this.requestPermissions(permissions)
    // Create events
    let date = new Date()
    for (let index = 0; index < 150; ++index) {
      let event: calendarManager.Event = {
        type: calendarManager.EventType.NORMAL,
        startTime: date.getTime(),
        endTime: date.getTime() + 60 * 60 * 1000,
        title: `Test${index}`
      };
      this.events.push(event)
    }
  }

  build() {
    Column() {
      // Create 3 calendar accounts: calendar1, calendar2, calendar3
      Button('createCalendar').onClick(() => {
        try {
          calendarMgr?.createCalendar(this.calendarAccount1, (err: BusinessError, data: calendarManager.Calendar) => {
            if (err) {
              console.error(`Failed to create calendar. Code: ${err.code}, message: ${err.message}`);
            } else {
              calendar1 = data;
            }
          });
          calendarMgr?.createCalendar(this.calendarAccount2, (err: BusinessError, data: calendarManager.Calendar) => {
            if (err) {
              console.error(`Failed to create calendar. Code: ${err.code}, message: ${err.message}`);
            } else {
              calendar2 = data;
            }
          });
          calendarMgr?.createCalendar(this.calendarAccount3, (err: BusinessError, data: calendarManager.Calendar) => {
            if (err) {
              console.error(`Failed to create calendar. Code: ${err.code}, message: ${err.message}`);
            } else {
              calendar3 = data
            }
          });
        } catch (error) {
          console.error(`Failed to create calendar. Code: ${error.code}, message: ${error.message}`);
        }
      })

      // Add 50 events to each calendar account
      Button('addEvent').onClick(() => {
        let res = chunkArray(this.events, 50)
        let first50 = res[0]
        let medium50 = res[1]
        let last50 = res[2]
        // Add events
        calendar1?.addEvents(first50)
        calendar2?.addEvents(medium50)
        calendar3?.addEvents(last50)
      })

      // deleteEvent - delete 50 events timing
      Button('deleteEvent').onClick(async () => {
        let events = await calendar1?.getEvents()
        if (events) {
          let start = new Date().getTime()
          console.info('event1 length', events?.length)
          for (let i = events.length - 1; i >= 0; i--) {
            await calendar1?.deleteEvent(events[i].id)
            if (i === events.length - 1){
              // deleteEvent 1 time: 32
              console.info(`deleteEvent 1 time: ${new Date().getTime() - start}`)
            }
            if (i === 0) {
              // deleteEvent 50 time: 910
              console.info(`deleteEvent 50 time: ${new Date().getTime() - start}`)
            }
          }
        }
      })

      // deleteEvents - delete 50 events timing
      Button('deleteEvents').onClick(async () => {
        let events = await calendar2?.getEvents()
        if (events) {
          let ids = events.map(event => event.id);
          let start = new Date().getTime()
          console.info('event2 length', ids?.length)
          await calendar2?.deleteEvents(ids)
          // deleteEvents time: 925
          console.info(`deleteEvents time: ${new Date().getTime() - start}`)
        }
      })

      // Delete calendar account timing
      Button('deleteCalendar').onClick(async () => {
        if (calendar3) {
          let events = await calendar3.getEvents()
          if (events) {
            console.info('event3 length', events?.length)
          }
          let start = new Date().getTime()
          await calendarMgr?.deleteCalendar(calendar3)
          // deleteCalendar time: 60
          console.info(`deleteCalendar time: ${new Date().getTime() - start}`)
        }
      })
    }
    .height('100%')
    .width('100%')
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • deleteCalendar() is the most efficient method when deleting all events under an account (~109ms for 50 events)
  • deleteevents() batch deletion is more efficient than multiple deleteEvent() calls (~852ms vs ~935ms)
  • Single deleteEvent() should be used only when deleting individual specific events
  • Consider business requirements when choosing deletion strategy for optimal performance

Written by Emincan Ozcan

Top comments (0)