안드로이드 캘린더 연동 앱 만들기 Part 2
밥벌이2011. 6. 2. 04:26
캘린더에 일정을 등록하는 방법에 대해선 지난번 Part 1에서 간단하게 소개했으니 이번엔 일단 일정 데이터를 가져 오는 방법에 대해서 살펴보자. 이전 파트에서 calendars를 가져왔던 것 처럼 events쪽 URI를 ContentResolver에 넘겨줘서 쿼리하면 된다.
// 이전 파트에서와 마찬가지로 일단 calendar를 하나 가져온다. final String CONTENT_URI = "content://com.android.calendar"; Uri uri = Uri.parse(CONTENT_URI + "/calendars"); Cursor c = getContentResolver().query( uri, new String[] { "_id" }, "selected=?", new String[] { "1" }, null); if(c == null || !c.moveToFirst()) { // 시스템에 캘린더가 존재하지 않음(계정이 등록되어 있지 않음) 오류 처리 필요 } final int id = c.getInt(c.getColumnIndex("_id")); c.close(); uri = Uri.parse(CONTENT_URI + "/events"); // 이전 파트에서 집어 넣었던 일정을 검색한다. c = getContentResolver().query( uri, new String[] { "_id", "dtstart" }, // 가져올 필드 "calendar_id=? AND title=?", new String[] { String.valueOf(id), "birthday" }, null); if(c == null || !c.moveToFirst()) { // 실패했거나 검색 결과가 없음. 오류처리 필요 } // 일정의 시작 시간을 Date타입인 dtstart에 저장한다. final Date dtstart = new Date(c.getLong(c.getColumnIndex("dtstart"))); c.close();
위와 같이 시스템에 들어 있는 일정 데이터를 가져 올 수 있다. 위의 dtstart의 경우는 epoch time 형식으로 값을 저장하고, 또 가져 올 수 있다. 추가로 다른 데이터를 가져 올려면 인자로 넘겨주는 컬럼 목록 배열에 해당 컬럼명을 추가해주어 가져 올 수 있다. 어차피 ContentResolver 를 사용하는 방식은 안드로이드에서 어떤 ContentProvider를 사용하건 동일한 거고, 각 테이블에 어떤 컬럼들이 존재하는지, 그리고 어떤 식으로 데이터를 저장하고 가져올 수 있는지를 아는 것이 중요하겠다. 일단 Event에 어떤 항목들이 존재하는 지를 살펴보자
Events 테이블의 컬럼 목록
사실 이 중에서 안 써본 것들도 많기 때문에 전부 다 자세히 설명할 수는 없다. 주의깊게 봐야 할 것은calendar_id라든가 deleted 컬럼이다. calendar_id는 현재 이벤트가 속한 캘린더의 _id 값이 들어 있어 foreign key 역할을 한다고 보면 되겠고, deleted 컬럼의 경우 해당 일정을 사용자가 삭제할 때 true 값이 된다. 즉, 안드로이드 ContentProvider에서는 실제 레코드를 날려버리지 않고 deleted 플래그를 세팅해서 지운 것처럼 표시한다. 만약 삭제한 일정을 가져오고 싶지 않다면 쿼리문에 deleted 필드가 0 인 것만 가져오도록 WHERE 조건을 추가해 줘야 하겠다. dtstart나 dtend는 Java.util.Date 인스턴스에 getTime() 호출해서 나오는 long 타입의 millisecond 값을 지정해 주고, 혹은 캘린더에서 가져온 값을 생성자에 넣어주는 것으로 쉽게 활용할 수 있다. 문제는 RFC2445 형식을 따르는 필드들일 것이다. 전부 설명하기는 좀 귀찮으니 rrule 필드만 우선적으로 설명한다. (exrule도 같은 형식이다) 나머지는 나중에 또 연재하게 되면 다시 다룰지 어쩔지는 모르겠다.
RFC2445에서는 rrule의 값을 recur라는 형식으로 지정하는데, 다음과 같이 정의하고 있다.
recur = "FREQ"=freq *(
; either UNTIL or COUNT may appear in a 'recur',; but UNTIL and COUNT MUST NOT occur in the same 'recur'
( ";" "UNTIL" "=" enddate ) /( ";" "COUNT" "=" 1*DIGIT ) /
; the rest of these keywords are optional,; but MUST NOT occur more than once
( ";" "INTERVAL" "=" 1*DIGIT ) /( ";" "BYSECOND" "=" byseclist ) /( ";" "BYMINUTE" "=" byminlist ) /( ";" "BYHOUR" "=" byhrlist ) /( ";" "BYDAY" "=" bywdaylist ) /( ";" "BYMONTHDAY" "=" bymodaylist ) /( ";" "BYYEARDAY" "=" byyrdaylist ) /( ";" "BYWEEKNO" "=" bywknolist ) /( ";" "BYMONTH" "=" bymolist ) /( ";" "BYSETPOS" "=" bysplist ) /( ";" "WKST" "=" weekday ) /( ";" x-name "=" text ))
freq = "SECONDLY" / "MINUTELY" / "HOURLY" / "DAILY"/ "WEEKLY" / "MONTHLY" / "YEARLY"
enddate = dateenddate =/ date-time ;An UTC value
byseclist = seconds / ( seconds *("," seconds) )
seconds = 1DIGIT / 2DIGIT ;0 to 59
byminlist = minutes / ( minutes *("," minutes) )
minutes = 1DIGIT / 2DIGIT ;0 to 59
byhrlist = hour / ( hour *("," hour) )
hour = 1DIGIT / 2DIGIT ;0 to 23
bywdaylist = weekdaynum / ( weekdaynum *("," weekdaynum) )
weekdaynum = [([plus] ordwk / minus ordwk)] weekday
plus = "+"
minus = "-"
ordwk = 1DIGIT / 2DIGIT ;1 to 53
weekday = "SU" / "MO" / "TU" / "WE" / "TH" / "FR" / "SA";Corresponding to SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,;FRIDAY, SATURDAY and SUNDAY days of the week.
bymodaylist = monthdaynum / ( monthdaynum *("," monthdaynum) )
monthdaynum = ([plus] ordmoday) / (minus ordmoday)
ordmoday = 1DIGIT / 2DIGIT ;1 to 31
byyrdaylist = yeardaynum / ( yeardaynum *("," yeardaynum) )
yeardaynum = ([plus] ordyrday) / (minus ordyrday)
ordyrday = 1DIGIT / 2DIGIT / 3DIGIT ;1 to 366
bywknolist = weeknum / ( weeknum *("," weeknum) )
weeknum = ([plus] ordwk) / (minus ordwk)
bymolist = monthnum / ( monthnum *("," monthnum) )
monthnum = 1DIGIT / 2DIGIT ;1 to 12
bysplist = setposday / ( setposday *("," setposday) )
setposday = yeardaynum
형식에 따르자면, "FREQ=" 라는 문자열이 반드시 맨 앞에 나와야 하고, 일정 반복 간격 문자열을 대항 feature에 지정한다. 가령 월간 단위라면 "FREQ=MONTHLY"가 되겠다. 그 후 옵션으로 여러가지를 지정해 줄 수 있는데 몇가지 써본 안드로이드 단말에서 rrule 값을 지정할 때 WKST 값을 꼭 지정해 줘야 기본 캘린더 앱에서 읽는데 무리가 없는 것 처럼 보였다. 따라서 별다른 옵션 없이 월간 반복되도록 룰을 만들어 주려면 "FREQ=MONTHLY;WKST=SU"와 같이 하면 된다. UNTIL이나 COUNT를 붙여 써서 언제까지 일정을 반복할 것인지 혹은 일정 반복 회수가 얼마인지를 지정해 줄 수 있으며 만약 월간 반복되며 3번 반복되는 일정을 만들겠다면 "FREQ=MONTHLY;COUNT=3;WKST=SU"가 되어야 한다. INTERVAL의 경우는 일정 반복 주기를 뜻하는데 기본 값은 1이고 이걸 만약 2로 지정하게 되면 FREQ에 지정한 반복 단위가 두번 경과 될 때 마다 일정이 반복되게 된다. 즉 앞선 예제에서 "FREQ=MONTHLY;COUNT=3;INTERVAL=2;WKST=SU"로 지정해 주면 두달 마다 한 번씩 총 6개월동안 반복되는 일정을 만들 수 있게 된다. BYXXX 시리즈들은 XXX가 해당 값이 될 때 반복되게 된다.
재미있는 건 안드로이드 캘린더의 필드들은 좀 중복되는 것들이 있다는 건데, 가령 rrule의 UNTIL/COUNT값과 lastDate가 중복되는 부분이 있고, duration과 dtend 값이 중복된다. 대체로 집어 넣는 건 선호하는 필드에만설정 값을 넣어도 기본 캘린더 앱이 알아서 잘 처리해 주곤 하지만 가져 올 때는 좀 얘기가 달라진다. 특정 값이 null이 될 때도 있고 안될 때도 있어서 중복되는 필드 모두 가져와서 값을 참조해 보고 잘 판단하여 써야한다.
이번 파트에 다루지 않은 duration 지정 형식은 RFC2445의 dur-value 정의를 참조하면 되고, UNTIL에 지정하는 date-time 형식도 살펴보자. 그다지 어렵진 않으니 쉽게 사용할 수 있을 것이다.
파트 2는 일단 여기까지. 3에선 연관 테이블에 대해서 살펴볼텐데... 언제 쓸 진 저도 모릅니다.
'밥벌이' 카테고리의 다른 글
안드로이드의 native stack trace의 활용 (0) | 2011.08.30 |
---|---|
안드로이드 Asset 사용에 있어 몇가지... (0) | 2011.08.05 |
안드로이드 캘린더 연동 앱 만들기 Part 1 (12) | 2011.03.24 |
리눅스에서 안드로이드 USB 디버깅 연결 설정하기 (0) | 2011.03.18 |
DexClassLoader를 사용한 다른 패키지의 클래스 로딩 (1) | 2011.03.02 |