有没有办法在不使用gdata-java-client的情况下访问日历的条目?

时间:2009-05-11 06:26:28

标签: android android-calendar

是否可以通过手机离线获取日历的条目?似乎唯一的方法是使用gdata-java-client

7 个答案:

答案 0 :(得分:9)

Josef和Isaac用于访问日历的解决方案仅适用于Android 2.1及更早版本。 Google已将2.2中的基本内容URI从“content:// calendar”更改为“content://com.android.calendar”。此更改意味着最好的方法是尝试使用旧的基本URI获取游标,如果返回的游标为null,则尝试新的基本URI。

请注意,我从Shane Conder和Lauren Darcey提供的open source test code Working With The Android Calendar文章中获得了这种方法。

private final static String BASE_CALENDAR_URI_PRE_2_2 = "content://calendar";
private final static String BASE_CALENDAR_URI_2_2 = "content://com.android.calendar";
/*
 * Determines if we need to use a pre 2.2 calendar Uri, or a 2.2 calendar Uri, and returns the base Uri
 */
private String getCalendarUriBase() {
    Uri calendars = Uri.parse(BASE_CALENDAR_URI_PRE_2_2 + "/calendars");
    try {
        Cursor managedCursor = managedQuery(calendars, null, null, null, null);
        if (managedCursor != null) {
            return BASE_CALENDAR_URI_PRE_2_2;
        }
        else {
            calendars = Uri.parse(BASE_CALENDAR_URI_2_2 + "/calendars");
            managedCursor = managedQuery(calendars, null, null, null, null);

            if (managedCursor != null) {
                return BASE_CALENDAR_URI_2_2;
            }
        }
    } catch (Exception e) { /* eat any exceptions */ }

    return null; // No working calendar URI found
}

答案 1 :(得分:8)

这些答案很好,但它们都涉及对Calendar URI进行硬编码(我在不同的Android设备上看到了三种不同的版本)。

更好的方法来获得URI(硬编码类和字段的名称)将是这样的:

Class<?> calendarProviderClass = Class.forName("android.provider.Calendar");
Field uriField = calendarProviderClass.getField("CONTENT_URI");
Uri calendarUri = (Uri) uriField.get(null);

这并不完美(如果删除android.provider.Calendar类或CONTENT_URI字段,它会中断)但它可以在比任何单个URI硬编码更多的平台上运行。

请注意,这些反射方法将抛出需要被调用方法捕获或重新抛出的exceptions

答案 2 :(得分:3)

您可以使用日历内容提供商(com.android.providers.calendar.CalendarProvider)。例如:


ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(Uri.parse("content://calendar/events"), null, null, null, null);

while(cursor.moveToNext()) {
    String eventTitle = cursor.getString(cursor.getColumnIndex("title"));
    Date eventStart = new Date(cursor.getLong(cursor.getColumnIndex("dtstart")));
    // etc.
}

编辑:您可能希望将其放在包装器中(请参阅Isaac's post),因为它目前是私有API。

答案 3 :(得分:3)

目前,如果不使用私有API,这是不可能的(请参阅Josef的帖子。)有一个日历提供程序,但它尚未公开。它可以随时更改并破坏您的应用程序 虽然,它可能不会改变(我认为它们不会从“日历”改变它),所以你可以使用它。但我的建议是使用这样一个单独的类:

public class CalendarProvider {
     public static final Uri CONTENT_URI = Uri.parse("content://calendar");
     public static final String TITLE = "title";
     public static final String ....

直接使用它们代替字符串。如果/当API发生变化或公开时,这将使您可以非常轻松地进行更改。

答案 4 :(得分:2)

您可以从此处使用CalendarContract:https://github.com/dschuermann/android-calendar-compatibility

它与Android 4上提供的API类相同,但适用于Android&gt; = 2.2。

答案 5 :(得分:1)

关于可以更改的API ...整个ContentProvider方法不会快速更改,因此只需更新字符串就可以克服许多问题。因此,创建在整个项目中重复使用的常量。

public static final String URI_CONTENT_CALENDAR_EVENTS = "content://calendar/events";

ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(Uri.parse(URI_CONTENT_CALENDAR_EVENTS), null, null, null, null);
    //etc

如果你想要一个合适的私人API,你必须创建一个pojo和一些像这样的服务:

public class CalendarEvent {
    private long id;
    private long date;
    //etc...
}

public interface CalendarService {

    public Set<CalendarEvent> getAllCalendarEvents();

    public CalendarEvent findCalendarEventById(long id);

    public CalendarEvent findCalendarEventByDate(long date);

}

等等。这样,您只需更新CalendarEvent对象和此服务,以防API发生变化。

答案 6 :(得分:1)

Nick的解决方案涉及managedQuery,它没有在Context类中定义。很多时候,当您在后台运行时,您会想要使用上下文对象。这是修改后的版本:

public String getCalendarUriBase(){

return(android.os.Build.VERSION.SDK_INT&gt; = 8)? “内容://com.android.calendar”: “内容://历”; }

不应在此处执行null的catch,因为即使managedQuery成功提前,也可能存在更多异常。