Есть ли способ получить доступ к записям календаря без использования gdata-java-client?

StackOverflow https://stackoverflow.com/questions/846942

  •  21-08-2019
  •  | 
  •  

Вопрос

Можно ли получить записи календаря с телефона в автономном режиме?Кажется, единственный способ - это использовать gdata-java-клиент.

Это было полезно?

Решение

Эти ответы хороши, но все они связаны с жестким кодированием 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 который нужно будет перехватить или повторно выбросить вызывающим методом.

Другие советы

Решения Джозефа и Исаака для доступа к календарю работают только в Android 2.1 и более ранних версиях.Google изменил базовый URI контента в 2.2 с "content://calendar" на "content://com.android.calendar".Это изменение означает, что наилучшим подходом является попытка получить курсор, используя старый базовый URI, и если возвращенный курсор равен null, то попробуйте использовать новый базовый URI.

Пожалуйста, обратите внимание, что я получил этот подход от тестовый код с открытым исходным кодом что Шейн Кондер и Лорен Дарси обеспечивают своим Работа с Календарем Android Статья.

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
}

В настоящее время это невозможно без использования частных API (см. Сообщение Джозефа.) Существует поставщик календаря, но он пока не является общедоступным.Это может измениться в любое время и привести к поломке вашего приложения.
Хотя, это, вероятно, не изменится (я не думаю, что они изменят его из "календаря"), так что вы, возможно, сможете им воспользоваться.Но моя рекомендация - использовать отдельный класс, подобный этому:

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

И используйте их непосредственно вместо строк.Это позволит вам очень легко изменить его, если / когда API изменится или станет общедоступным.

Вы можете использовать поставщика контента календаря (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.
}

Редактировать:возможно, вы захотите поместить это в оболочку (см. Сообщение Исаака) поскольку в настоящее время это частный API.

Вы можете использовать CalendarContract отсюда: https://github.com/dschuermann/android-calendar-compatibility

Это тот же класс API, что и на Android 4, но созданный для работы с Android >= 2.2.

Об 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.

Решение Ника включает managedQuery, который не определен в классе Context.Много раз, когда вы запускаете что-то в фоновом режиме, вам хотелось бы использовать контекстный объект.Вот измененная версия:

общедоступная строка getCalendarUriBase() {

вернуть (android.os.Build.ВЕРСИЯ.SDK_INT>=8)?"содержимое://com.android.calendar":"содержание://календарь";}

Перехват для null не следует выполнять здесь, поскольку может быть больше исключений, даже если управляемый запрос был выполнен успешно ранее.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top