Calendario Xamarin.Android
API Calendario
Un nuovo set di API di calendario introdotte in Android 4 supporta applicazioni progettate per leggere o scrivere dati nel provider di calendario. Queste API supportano un'ampia gamma di opzioni di interazione con i dati del calendario, tra cui la possibilità di leggere e scrivere eventi, partecipanti e promemoria. Usando il provider di calendario nell'applicazione, i dati aggiunti tramite l'API verranno visualizzati nell'app calendario predefinita fornita con Android 4.
Aggiunta di autorizzazioni
Quando si lavora con le nuove API del calendario nell'applicazione, la prima cosa da fare è aggiungere le autorizzazioni appropriate al manifesto Android. Le autorizzazioni da aggiungere sono android.permisson.READ_CALENDAR
e android.permission.WRITE_CALENDAR
, a seconda che si stia leggendo e/o scrivendo dati del calendario.
Utilizzo del contratto di calendario
Dopo aver impostato le autorizzazioni, è possibile interagire con i dati del calendario usando la CalendarContract
classe . Questa classe fornisce un modello di dati che le applicazioni possono usare quando interagiscono con il provider di calendario. CalendarContract
consente alle applicazioni di risolvere gli URI in entità di calendario, ad esempio calendari ed eventi. Offre anche un modo per interagire con vari campi in ogni entità, ad esempio il nome e l'ID di un calendario o la data di inizio e di fine di un evento.
Di seguito è riportato un esempio che usa l'API Calendario. In questo esempio si esaminerà come enumerare i calendari e i relativi eventi, nonché come aggiungere un nuovo evento a un calendario.
Elenco calendari
Prima di tutto, esaminiamo come enumerare i calendari registrati nell'app calendario. A tale scopo, è possibile creare un'istanza di .CursorLoader
Introdotto in Android 3.0 (API 11), CursorLoader
è il modo preferito per usare un oggetto ContentProvider
. Come minimo, è necessario specificare l'URI del contenuto per i calendari e le colonne da restituire; questa specifica di colonna è nota come proiezione.
La chiamata al CursorLoader.LoadInBackground
metodo consente di eseguire una query su un provider di contenuti per i dati, ad esempio il provider di calendario.
LoadInBackground
esegue l'operazione di caricamento effettiva e restituisce un oggetto Cursor
con i risultati della query.
Ci CalendarContract
aiuta a specificare sia il contenuto Uri
che la proiezione. Per ottenere il contenuto Uri
per l'esecuzione di query sui calendari, è sufficiente usare la CalendarContract.Calendars.ContentUri
proprietà come segue:
var calendarsUri = CalendarContract.Calendars.ContentUri;
L'uso di CalendarContract
per specificare le colonne del calendario desiderate è altrettanto semplice. È sufficiente aggiungere campi nella CalendarContract.Calendars.InterfaceConsts
classe a una matrice. Ad esempio, il codice seguente include l'ID del calendario, il nome visualizzato e il nome dell'account:
string[] calendarsProjection = {
CalendarContract.Calendars.InterfaceConsts.Id,
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName
};
È Id
importante includere se si usa un SimpleCursorAdapter
oggetto per associare i dati all'interfaccia utente, come si vedrà a breve. Con l'URI del contenuto e la proiezione sul posto, viene creata un'istanza del CursorLoader
metodo e viene chiamato il CursorLoader.LoadInBackground
metodo per restituire un cursore con i dati del calendario, come illustrato di seguito:
var loader = new CursorLoader(this, calendarsUri, calendarsProjection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();
L'interfaccia utente di questo esempio contiene un oggetto ListView
, con ogni elemento nell'elenco che rappresenta un singolo calendario. Il codice XML seguente illustra il markup che include :ListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@android:id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Inoltre, è necessario specificare l'interfaccia utente per ogni elemento di elenco, che viene inserito in un file XML separato come indicato di seguito:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/calDisplayName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dip" />
<TextView android:id="@+id/calAccountName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12dip" />
</LinearLayout>
Da questo punto in poi, è solo normale codice Android per associare i dati dal cursore all'interfaccia utente. Verrà usato come SimpleCursorAdapter
segue:
string[] sourceColumns = {
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName };
int[] targetResources = {
Resource.Id.calDisplayName, Resource.Id.calAccountName };
SimpleCursorAdapter adapter = new SimpleCursorAdapter (this,
Resource.Layout.CalListItem, cursor, sourceColumns, targetResources);
ListAdapter = adapter;
Nel codice precedente, l'adattatore accetta le colonne specificate nella sourceColumns
matrice e le scrive negli elementi dell'interfaccia utente nella matrice per ogni voce del targetResources
calendario nel cursore. L'attività usata qui è una sottoclasse di ListActivity
, che include la ListAdapter
proprietà a cui è stato impostato l'adapter.
Ecco uno screenshot che mostra il risultato finale, con le informazioni sul calendario visualizzate in ListView
:
Elenco di eventi del calendario
Verrà ora illustrato come enumerare gli eventi per un determinato calendario. Basandosi sull'esempio precedente, verrà presentato un elenco di eventi quando l'utente seleziona uno dei calendari. Sarà quindi necessario gestire la selezione dell'elemento nel codice precedente:
ListView.ItemClick += (sender, e) => {
int i = (e as ItemEventArgs).Position;
cursor.MoveToPosition(i);
int calId =
cursor.GetInt (cursor.GetColumnIndex (calendarsProjection [0]));
var showEvents = new Intent(this, typeof(EventListActivity));
showEvents.PutExtra("calId", calId);
StartActivity(showEvents);
};
In questo codice viene creata una finalità per aprire un'attività di tipo EventListActivity
, passando l'ID del calendario nella finalità. Sarà necessario l'ID per sapere quale calendario eseguire una query per gli eventi. EventListActivity
Nel metodo di OnCreate
è possibile recuperare l'ID da Intent
come illustrato di seguito:
_calId = Intent.GetIntExtra ("calId", -1);
Eseguire ora una query sugli eventi per questo ID calendario. Il processo di query per gli eventi è simile al modo in cui è stata eseguita una query per un elenco di calendari in precedenza, solo questa volta si userà la CalendarContract.Events
classe . Il codice seguente crea una query per recuperare gli eventi:
var eventsUri = CalendarContract.Events.ContentUri;
string[] eventsProjection = {
CalendarContract.Events.InterfaceConsts.Id,
CalendarContract.Events.InterfaceConsts.Title,
CalendarContract.Events.InterfaceConsts.Dtstart
};
var loader = new CursorLoader(this, eventsUri, eventsProjection,
String.Format ("calendar_id={0}", _calId), null, "dtstart ASC");
var cursor = (ICursor)loader.LoadInBackground();
In questo codice si ottiene prima di tutto il contenuto Uri
per gli eventi dalla CalendarContract.Events.ContentUri
proprietà . Specificare quindi le colonne evento da recuperare nella matrice eventsProjection.
Infine, viene creata un'istanza di con CursorLoader
queste informazioni e viene chiamato il metodo del LoadInBackground
caricatore per restituire un Cursor
oggetto con i dati dell'evento.
Per visualizzare i dati dell'evento nell'interfaccia utente, è possibile usare markup e codice come in precedenza per visualizzare l'elenco dei calendari. Anche in questo caso, viene usato SimpleCursorAdapter
per associare i dati a un oggetto ListView
come illustrato nel codice seguente:
string[] sourceColumns = {
CalendarContract.Events.InterfaceConsts.Title,
CalendarContract.Events.InterfaceConsts.Dtstart };
int[] targetResources = {
Resource.Id.eventTitle,
Resource.Id.eventStartDate };
var adapter = new SimpleCursorAdapter (this, Resource.Layout.EventListItem,
cursor, sourceColumns, targetResources);
adapter.ViewBinder = new ViewBinder ();
ListAdapter = adapter;
La differenza principale tra questo codice e il codice usato in precedenza per mostrare l'elenco di calendari è l'uso di un ViewBinder
oggetto , impostato sulla riga:
adapter.ViewBinder = new ViewBinder ();
La ViewBinder
classe consente di controllare ulteriormente il modo in cui si associano valori alle visualizzazioni. In questo caso, viene usato per convertire l'ora di inizio dell'evento da millisecondi a una stringa di data, come illustrato nell'implementazione seguente:
class ViewBinder : Java.Lang.Object, SimpleCursorAdapter.IViewBinder
{
public bool SetViewValue (View view, Android.Database.ICursor cursor,
int columnIndex)
{
if (columnIndex == 2) {
long ms = cursor.GetLong (columnIndex);
DateTime date = new DateTime (1970, 1, 1, 0, 0, 0,
DateTimeKind.Utc).AddMilliseconds (ms).ToLocalTime ();
TextView textView = (TextView)view;
textView.Text = date.ToLongDateString ();
return true;
}
return false;
}
}
Viene visualizzato un elenco di eventi, come illustrato di seguito:
Aggiunta di un evento di calendario
Si è visto come leggere i dati del calendario. Vediamo ora come aggiungere un evento a un calendario. Per il funzionamento, assicurarsi di includere l'autorizzazione android.permission.WRITE_CALENDAR
menzionata in precedenza. Per aggiungere un evento a un calendario, si eseguirà quanto riportato di seguito:
- Creare un'istanza di
ContentValues
. - Usare le chiavi della
CalendarContract.Events.InterfaceConsts
classe per popolare l'istanzaContentValues
. - Impostare i fusi orari per l'ora di inizio e di fine dell'evento.
- Utilizzare un
ContentResolver
oggetto per inserire i dati dell'evento nel calendario.
Il codice seguente illustra questi passaggi:
ContentValues eventValues = new ContentValues ();
eventValues.Put (CalendarContract.Events.InterfaceConsts.CalendarId,
_calId);
eventValues.Put (CalendarContract.Events.InterfaceConsts.Title,
"Test Event from M4A");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Description,
"This is an event created from Xamarin.Android");
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtstart,
GetDateTimeMS (2011, 12, 15, 10, 0));
eventValues.Put (CalendarContract.Events.InterfaceConsts.Dtend,
GetDateTimeMS (2011, 12, 15, 11, 0));
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone,
"UTC");
eventValues.Put(CalendarContract.Events.InterfaceConsts.EventEndTimezone,
"UTC");
var uri = ContentResolver.Insert (CalendarContract.Events.ContentUri,
eventValues);
Si noti che se non si imposta il fuso orario, verrà generata un'eccezione di tipo Java.Lang.IllegalArgumentException
. Poiché i valori dell'ora dell'evento devono essere espressi in millisecondi dall'epoca, viene creato un GetDateTimeMS
metodo (in ) per convertire le specifiche di data in EventListActivity
formato millisecondo:
long GetDateTimeMS (int yr, int month, int day, int hr, int min)
{
Calendar c = Calendar.GetInstance (Java.Util.TimeZone.Default);
c.Set (Java.Util.CalendarField.DayOfMonth, 15);
c.Set (Java.Util.CalendarField.HourOfDay, hr);
c.Set (Java.Util.CalendarField.Minute, min);
c.Set (Java.Util.CalendarField.Month, Calendar.December);
c.Set (Java.Util.CalendarField.Year, 2011);
return c.TimeInMillis;
}
Se aggiungiamo un pulsante all'interfaccia utente dell'elenco eventi ed eseguiamo il codice precedente nel gestore eventi click del pulsante, l'evento viene aggiunto al calendario e aggiornato nell'elenco, come illustrato di seguito:
Se si apre l'app calendario, si noterà che l'evento viene scritto anche in questa posizione:
Come si può notare, Android consente un accesso potente e semplice per recuperare e rendere persistenti i dati del calendario, consentendo alle applicazioni di integrare facilmente le funzionalità del calendario.