4 komentarze

Content Providers – dostęp do danych przy pomocy dostawców treści

Sierpień 29, 2011 Content Providers Podstawowe komponenty Tutoriale

Dostawcy treści w Androidzie to abstrakcyjna warstwa ułatwiająca dostęp do danych zapisanych w urządzeniu. Content Providers (ang.) dostarczają nam interfejsu zarządzania danymi opartego o adresy URI (które wykorzystują schemat content://). Dzięki nim w łatwy sposób możemy oddzielić warstwę aplikacji od warstwy dostępu do danych. Co więcej, mechanizm ten pozwala nam na dzielenie się danymi pomiędzy wszystkimi aplikacjami działającymi w systemie (i posiadającymi odpowiednie uprawnienia).

Android sam w sobie posiada kilku wbudowanych dostawców treści, którzy ułatwiają nam dostęp m.in. do:

  • Kontaktów,
  • Historii połączeń
  • Danych multimedialnych (muzyka, zdjęcia)
  • Ustawień

Każde z powyższych (i wiele innych) posiada własną bazę danych SQLite umieszczoną w pamięci naszego urządzenia. Dzięki dostawcom, dostęp do powyższych danych jest ustandaryzowany i możliwy z każdej aplikacji naszego urządzenia. I, co najważniejsze, jest na tyle prosty, że po zapoznaniu z jednym z dostawców, będziemy potrafili korzystać z każdego innego.

Dzisiejszy wpis będzie wprowadzeniem do obsługi dostawców treści (na przykładzie dostępu do listy kontaktów).

Adresy URI

Dostęp do danych za pomocą dostawców treści opiera się o adresację URI. Na ich podstawie określany jest zarówno konkretny dostawca, z którego chcemy skorzystać jak i dane, które chcemy wydobyć (ich zbiór lub pojedynczy rekord).

Każdy adres URI składa się z 3 części – (1)content://(2)<nazwa dostawcy>/(3)<pozostałe segmenty adresu>

  1. content:// – to stały prefiks mówiący o tym, że chcemy skorzystać z dostawcy danych
  2. <nazwa dostawcy>/ – segment wskazujący na konkretnego dostawcę danych. Na jego podstawie określany jest dostawca, którego będziemy prosić o dane.
    Istnieją dwa typy powyższego segmentu:
    1. Proste, czyli składające się najczęściej z jednego słowa (media, contacts, itp). Określają one dostawców treści dostarczonych przez twórców systemu.
    2. Złożone – ich nazwa to najczęściej pełna nazwa klasy dostawcy (wraz z pakietem). Są to dostawcy zdefiniowani przez niezależnych twórców aplikacji. Przykład takiego adresu to content://com.example.provider.myprovider/.
  3. <pozostałe segmenty adresu> – tutaj określamy dane jakie chcemy uzyskać. Ta część adresu może składać się z jednego lub więcej segmentów. Za ich pomocą możemy określać zarówno zbiór danych jak i pojedyncze rekordy. Przykładowe adresy to:
    • content://com.android.contacts/contacts/7 – wskazuje na konkretny kontakt (o id = 7)
    • content://com.example.provider.myprovider/items – wskazuje na cały zbiór danych (tablę) items.

Warto wspomnieć o tym, że adresy URI mogą być nieco bardziej złożone od tych, które przedstawiłem powyżej. Oprócz wszystkich i pojedynczego rekordu można również wstępnie definiować filtry dla zbioru danych itp. Dostawcy treści mają możliwość traktowania każdego segmentu jako osobnego argumentu dla funkcji przetwarzających dane, w związku z czym mamy tu ogromne pole manewru.

Dostęp do danych

Do uzyskania dostępu do danych wykorzystywany jest mechanizm ContentResolver. Dostarcza nam on wszystkich potrzebnych metod umożliwiających operacje na danych (odczyt, zapis, usuwanie, aktualizowanie). Każdy kontekst aplikacji przechowuje instancję klasy ContentResolver, do której dostęp odbywa się poprzez wywołanie metody getContentResolver() (możemy ją wywołać zarówno na kontekście całej aplikacji jak i kontekście konkretnego komponentu – np. Aktywności).

ContentResolver contentResolver = getContentResolver();

Metody klasy ContentResolver, które operują na danych (np. query(), insert(), delete(), update()) jako jeden z argumentów przyjmują adres URI. Na jego podstawie ContentResolver decyduje z którego dostawcy treści ma skorzystać.

Pobieranie danych

Dostęp do danych za pomocą dostawców treści jest bardzo podobny do standardowych zapytań SQL. Dane zwracane są w postaci obiektu Cursor, który pozwala nam na „chodzenie” po wszystkich zwróconych wierszach danych (dokumentacja klasy Cursor).

Oto typowe zapytanie pobierające zbiór kontaktów z naszego urządzenia:

private Cursor getContactsCursor() {
	Uri uri = RawContacts.CONTENT_URI;
	String[] projection = { RawContacts._ID, Contacts.DISPLAY_NAME };
	String selection = RawContacts.DELETED + "=?";
	String[] selectionArgs = { Integer.toString(0) };
	String sortOrder = Contacts.DISPLAY_NAME + " ASC";
	return contentResolver.query(uri, projection, selection, selectionArgs, sortOrder);
}

Metoda zwraca nam obiekt kursora w którym przechowywane są wszystkie zwrócone rekordy. Argumenty metody query() to (w kolejności):

  • Adres URI wskazujący na dostawcę treści i dane. W przykładzie korzystamy z tabeli RawContacts (dokumentacja). Przechowuje ona informacje o pojedynczym kontakcie (tzw. surowy kontakt). Czasami prawdziwy kontakt w telefonie składa się ze zbioru kilku surowych kontaktów.
  • Tablica projection – przechowuje ona nazwy kolumn, które chcemy pobrać w naszym zapytaniu. Jeżeli ustawimy ją na null (nie polecane bez uzasadnienia) zwrócone zostaną wszystkie dostępne kolumny z tabeli.
  • Ciąg selection – odpowiada klauzuli WHERE z języka SQL. Możemy wykorzystywać tu znak zapytania jako argument, do którego następnie zostaną wpisane dane z kolejnego argumentu – selectionArgs.
  • Tablica selectionArgs – argumenty wykorzystywane w ciągu selection. Wpisywane są w takiej samej kolejności, w jakiej są zadeklarowane.
  • Ciąg sortOrder – odpowiada klauzuli ORDER BY języka SQL.

Powyższy kod źródłowy zwróci nam wszystkie surowe kontakty, które nie zostały oznaczone jako „do usunięcia”. Zwrócone zostaną dwie kolumny – id oraz wyświetlana nazwa. Posortowane zostaną w kolejności alfabetycznej.

Dodawanie danych

Aby dodać dane za pomocą dostawcy treści, oprócz zdefiniowanego adresu URI (wskazującego na miejsce, gdzie dane mają być zapisane) powinniśmy dostarczyć obiekt klasy ContentValues. Przechowuje on pary klucz-wartość odpowiadające nazwie kolumny i wartości, która ma być do niej wpisana.

Przykładowy kod dodający do bazy surowy kontakt (posiadający jedynie imię i nazwisko) wygląda mniej więcej tak:

private void addNewContact() {
	String firstName = dialogEtFirstName.getText().toString();
	String lastName = dialogEtLastName.getText().toString();
	ContentValues values = new ContentValues();

	Uri rawContactUri = contentResolver.insert(RawContacts.CONTENT_URI, values);
	long rawContactId = ContentUris.parseId(rawContactUri);

	values.clear();
	values.put(RawContacts.Data.RAW_CONTACT_ID, rawContactId);
	values.put(RawContacts.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
	values.put(StructuredName.DISPLAY_NAME, firstName + " " + lastName);
	contentResolver.insert(Data.CONTENT_URI, values);
}

Jak widać, wykonywane tu są dwa zapytania. Jedno tworzy nowy kontakt (bez żadnych danych). Drugie natomiast, na podstawie zwróconego adresu URI (metoda insert zwraca adres URI wskazujący na nowo dodany rekord) dodaje dane dodatkowe, w postaci imienia i nazwiska.

Aktualizacja danych

Aktualizacja danych również polega na wykorzystaniu adresu URI oraz zbioru danych ContentValues. Dodatkowo należy dostarczyć warunek, na podstawie którego wiadomo będzie, które wiersze należy zaktualizować. Zaktualizowane zostaną wszystkie kolumny na które wskazuje ContentValues we wszystkich wierszach pasujących do warunku.

Przykład metody aktualizującej imię oraz nazwisko surowego kontaktu wygląda tak:

private void updateCurrentContact() {
	String firstName = dialogEtFirstName.getText().toString();
	String lastName = dialogEtLastName.getText().toString();
	ContentValues values = new ContentValues();
	values.put(CommonDataKinds.StructuredName.GIVEN_NAME, firstName);
	values.put(CommonDataKinds.StructuredName.FAMILY_NAME, lastName);
	values.put(CommonDataKinds.StructuredName.DISPLAY_NAME, firstName + " " + lastName);
	String where = ContactsContract.Data.RAW_CONTACT_ID + "=? AND "
			+ ContactsContract.Data.MIMETYPE + "=?";
	String[] selectionArgs = {
			Long.toString(contactId),
			CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
	};
	contentResolver.update(ContactsContract.Data.CONTENT_URI, values, where, selectionArgs);
}

Zgodnie z powyższym kodem zaktualizowane zostaną kolumny GIVEN_NAME, FAMILY_NAME, oraz DISPLAY_NAME wierszy, których id kontaktu będzie równe zmiennej contactId.

Metoda update() zwróci nam ilość zaktualizowanych wierszy.

Usuwanie danych

Usuwanie jest chyba najprostszą czynnością. Metodzie delete() należy dostarczyć jedynie adres URI oraz warunek, który wiersze muszą spełnić aby zostać usuniętym. Przykład usuwający pojedynczy kontakt wygląda tak:

private void deleteCurrentContact() {
	String where = RawContacts._ID + "=" + contactId;
	contentResolver.delete(RawContacts.CONTENT_URI, where, null);
}

Przykładowa aplikacja

Powyższe operacje wykorzystamy w prostej aplikacji, która pozwoli na dodawanie, usuwanie oraz edytowanie kontaktów.

Layout

Zaczniemy od stworzenia layoutu dla czterech elementów – okna Aktywności, wiersza w ListView, okna dialogowego dla edycji oraz dodawania kontaktu.

main.xml

<?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:layout_height="fill_parent"
		android:layout_weight="1"
		android:layout_width="fill_parent"
		android:id="@android:id/list"
		android:drawSelectorOnTop="false"></ListView>
	<Button
		android:layout_height="wrap_content"
		android:layout_width="fill_parent"
		android:id="@+id/btnAddNewContact"
		android:text="Add new contact"></Button>
</LinearLayout>

contact_row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:orientation="horizontal"
	android:layout_height="50dp"
	android:padding="2dp">
	<TextView
		android:textAppearance="?android:attr/textAppearanceMedium"
		android:id="@+id/tvDisplayName"
		android:layout_weight="1"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		android:gravity="center_vertical"
		android:layout_marginRight="1dp"
		android:paddingLeft="10dp"
		android:text="---"></TextView>
	<ImageButton
		android:src="@android:drawable/ic_menu_edit"
		android:layout_height="fill_parent"
		android:layout_width="50dp"
		android:layout_marginRight="1dp"
		android:id="@+id/ibEdit"
		android:background="@android:drawable/list_selector_background"></ImageButton>
	<ImageButton
		android:src="@android:drawable/ic_delete"
		android:layout_height="fill_parent"
		android:layout_width="50dp"
		android:id="@+id/ibDelete"
		android:background="@android:drawable/list_selector_background"></ImageButton>
</LinearLayout>

new_contact_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:id="@+id/layout_root">
	<TextView
		android:layout_width="wrap_content"
		android:textAppearance="?android:attr/textAppearanceMedium"
		android:layout_height="wrap_content"
		android:padding="5dp"
		android:text="Firstname"></TextView>
	<EditText
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:inputType="textPersonName"
		android:id="@+id/etFirstNameAdd"
		android:hint="Type firstname here...">
		<requestFocus></requestFocus>
	</EditText>
	<TextView
		android:id="@+id/textView2"
		android:layout_width="wrap_content"
		android:textAppearance="?android:attr/textAppearanceMedium"
		android:layout_height="wrap_content"
		android:padding="5dp"
		android:text="Lastname"></TextView>
	<EditText
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:inputType="textPersonName"
		android:id="@+id/etLastNameAdd"
		android:hint="Type lastname here..."></EditText>
</LinearLayout>

edit_contact_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:id="@+id/layout_root">
	<TextView
		android:layout_width="wrap_content"
		android:textAppearance="?android:attr/textAppearanceMedium"
		android:layout_height="wrap_content"
		android:padding="5dp"
		android:text="Firstname"></TextView>
	<EditText
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:inputType="textPersonName"
		android:id="@+id/etFirstNameEdit">
		<requestFocus></requestFocus>
	</EditText>
	<TextView
		android:id="@+id/textView2"
		android:layout_width="wrap_content"
		android:textAppearance="?android:attr/textAppearanceMedium"
		android:layout_height="wrap_content"
		android:padding="5dp"
		android:text="Lastname"></TextView>
	<EditText
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:inputType="textPersonName"
		android:id="@+id/etLastNameEdit"></EditText>
</LinearLayout>

Adapter listy kontaktów

Adapter listy kontaktów zbudowany jest zgodnie z zasadami wydajnościowymi (recykling widoku, jednokrotne wykonanie findViewById()). Artykuł z tym związany można przeczytać pod tym adresem.

Zaznaczony kod źródłowy odpowiedzialny jest za obsługę kliknięć przycisków dla poszczególnych wierszy listy.

package pl.froger.hello.contentprovider;

import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract.Contacts;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;

public class ContactListAdapter extends SimpleCursorAdapter {
	private Context context;
	private Cursor c;
	private int displayNameColumnIndex;

	private OnClickListener onItemEditClickListener;
	private OnClickListener onItemDeleteClickListener;

	public ContactListAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
		super(context, layout, c, from, to);
		this.context = context;
		this.c = c;
		displayNameColumnIndex = c.getColumnIndex(Contacts.DISPLAY_NAME);
	}

	static class ViewHolder {
		TextView tvDisplayName;
		ImageButton ibEditContact;
		ImageButton ibDeleteContact;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder viewHolder;
		View rowView = convertView;
		if(rowView == null) {
			LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			rowView = layoutInflater.inflate(R.layout.contact_row, null, true);
			viewHolder = new ViewHolder();
			viewHolder.tvDisplayName = (TextView) rowView.findViewById(R.id.tvDisplayName);
			viewHolder.ibEditContact = (ImageButton) rowView.findViewById(R.id.ibEdit);
			viewHolder.ibDeleteContact = (ImageButton) rowView.findViewById(R.id.ibDelete);
			viewHolder.ibEditContact.setOnClickListener(new OnClickListener() {
				public void onClick(View v) {
					if(onItemEditClickListener != null) onItemEditClickListener.onClick(v);
				}
			});
			viewHolder.ibDeleteContact.setOnClickListener(new OnClickListener() {
				public void onClick(View v) {
					if(onItemDeleteClickListener != null) onItemDeleteClickListener.onClick(v);
				}
			});
			rowView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) rowView.getTag();
		}
		c.moveToPosition(position);
		viewHolder.tvDisplayName.setText(c.getString(displayNameColumnIndex));
		viewHolder.ibEditContact.setTag(new Integer(position));
		viewHolder.ibDeleteContact.setTag(new Integer(position));
		return rowView;
	}

	public void setOnItemDeleteClickListener(
			OnClickListener onItemDeleteClickListner) {
		this.onItemDeleteClickListener = onItemDeleteClickListner;
	}

	public void setOnItemEditClickListener(
			OnClickListener onItemEditClickListener) {
		this.onItemEditClickListener = onItemEditClickListener;
	}
}

Kod źródłowy Aktywności

Oto kompletny kod źródłowy głównej Aktywności. Wykorzystane tu zostały metody opisane w niniejszym wpisie (podkreślone w kodzie).

package pl.froger.hello.contentprovider;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends ListActivity {
	private static final int DIALOG_EDIT = 1;
	private static final int DIALOG_DELETE = 2;
	private static final int DIALOG_CREATE = 3;

	private Button btnAddNewContact;
	private View editDialogView;
	private View addDialogView;
	private EditText dialogEtFirstNameEdit;
	private EditText dialogEtLastNameEdit;
	private EditText dialogEtFirstNameAdd;
	private EditText dialogEtLastNameAdd;

	private ContentResolver contentResolver;
	private Cursor contactsCursor;
	private ContactListAdapter adapter;
	private int currentContactPosition = 0;

	private OnClickListener onItemDeleteClickListener = new OnClickListener() {
		public void onClick(View v) {
			currentContactPosition = (Integer) v.getTag();
			showDialog(DIALOG_DELETE);
		}
	};

	private OnClickListener onItemEditClickListener = new OnClickListener() {
		public void onClick(View v) {
			currentContactPosition = (Integer) v.getTag();
			contactsCursor.moveToPosition(currentContactPosition);
			dialogEtFirstNameEdit.setText(getFirstNameOfCurrentContact());
			dialogEtLastNameEdit.setText(getLastNameOfCurrentContact());
			showDialog(DIALOG_EDIT);
		}
	};

	private String getFirstNameOfCurrentContact() {
		String displayName = contactsCursor.getString(1);
		String[] tokens = displayName.split(" ");
		if(tokens != null && tokens.length > 0) {
			return tokens[0];
		}
		return "";
	}

	private String getLastNameOfCurrentContact() {
		String displayName = contactsCursor.getString(1);
		String[] tokens = displayName.split(" ");
		if(tokens != null && tokens.length > 1) {
			return tokens[tokens.length - 1];
		}
		return "";
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		btnAddNewContact = (Button) findViewById(R.id.btnAddNewContact);
		btnAddNewContact.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				dialogEtFirstNameEdit.setText("");
				dialogEtLastNameEdit.setText("");
				showDialog(DIALOG_CREATE);
			}
		});
		initDialogViews();
		initDialogFields();
		contentResolver = getContentResolver();
		contactsCursor = getContactsCursor();
		startManagingCursor(contactsCursor);
		fillListView();
	}

	private void initDialogViews() {
		LayoutInflater inflater = this.getLayoutInflater();
		addDialogView = inflater.inflate(R.layout.new_contact_dialog,
				(ViewGroup) findViewById(R.id.layout_root));
		editDialogView = inflater.inflate(R.layout.edit_contact_dialog,
				(ViewGroup) findViewById(R.id.layout_root));
	}

	private void initDialogFields() {
		dialogEtFirstNameEdit = (EditText) editDialogView.findViewById(R.id.etFirstNameEdit);
		dialogEtLastNameEdit = (EditText) editDialogView.findViewById(R.id.etLastNameEdit);
		dialogEtFirstNameAdd = (EditText) addDialogView.findViewById(R.id.etFirstNameAdd);
		dialogEtLastNameAdd = (EditText) addDialogView.findViewById(R.id.etLastNameAdd);
	}

	private Cursor getContactsCursor() {
		Uri uri = RawContacts.CONTENT_URI;
		String[] projection = { RawContacts._ID, Contacts.DISPLAY_NAME };
		String selection = RawContacts.DELETED + "=?";
		String[] selectionArgs = { Integer.toString(0) };
		String sortOrder = Contacts.DISPLAY_NAME + " ASC";
		return contentResolver.query(uri, projection, selection, selectionArgs, sortOrder);
	}

	private void fillListView() {
		adapter = new ContactListAdapter(getApplicationContext(), R.layout.contact_row,
				contactsCursor,	new String[0], new int[0]);
		adapter.setOnItemDeleteClickListener(onItemDeleteClickListener);
		adapter.setOnItemEditClickListener(onItemEditClickListener);
		setListAdapter(adapter);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DIALOG_EDIT:
			return getEditDialog();
		case DIALOG_DELETE:
			return getDeleteDialog();
		case DIALOG_CREATE:
			return getCreateDialog();
		default:
			return null;
		}
	}

	private Dialog getEditDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		contactsCursor.moveToPosition(currentContactPosition);
		builder.setTitle("Edit contact");
		builder.setView(editDialogView);
		builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				updateCurrentContact();
				adapter.notifyDataSetChanged();
			}
		});
		builder.setNegativeButton("Cancel", null);
		return builder.create();
	}

	private void updateCurrentContact() {
		contactsCursor.moveToPosition(currentContactPosition);
		long contactId = contactsCursor.getLong(0);
		String firstName = dialogEtFirstNameEdit.getText().toString();
		String lastName = dialogEtLastNameEdit.getText().toString();
		ContentValues values = new ContentValues();
		values.put(CommonDataKinds.StructuredName.GIVEN_NAME, firstName);
		values.put(CommonDataKinds.StructuredName.FAMILY_NAME, lastName);
		values.put(CommonDataKinds.StructuredName.DISPLAY_NAME, firstName + " " + lastName);
		String where = ContactsContract.Data.RAW_CONTACT_ID + "=? AND "
				+ ContactsContract.Data.MIMETYPE + "=?";
		String[] selectionArgs = {
				Long.toString(contactId),
				CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
		};
		contentResolver.update(ContactsContract.Data.CONTENT_URI, values, where, selectionArgs);
	}

	private Dialog getDeleteDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Are you sure ?");
		builder.setMessage("Do you really want to delete this contact?");
		builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				deleteCurrentContact();
				adapter.notifyDataSetChanged();
			}
		});
		builder.setNegativeButton("No", null);
		return builder.create();
	}

	private void deleteCurrentContact() {
		contactsCursor.moveToPosition(currentContactPosition);
		long contactId = contactsCursor.getLong(0);
		String where = RawContacts._ID + "=" + contactId;
		contentResolver.delete(RawContacts.CONTENT_URI, where, null);
	}

	private Dialog getCreateDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Create new contact");
		builder.setView(addDialogView);
		dialogEtFirstNameAdd.setText("");
		dialogEtLastNameAdd.setText("");
		builder.setPositiveButton("Add", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				addNewContact();
				adapter.notifyDataSetChanged();
			}
		});
		builder.setNegativeButton("Cancel", null);
		return builder.create();
	}

	private void addNewContact() {
		String firstName = dialogEtFirstNameAdd.getText().toString();
		String lastName = dialogEtLastNameAdd.getText().toString();
		ContentValues values = new ContentValues();

		Uri rawContactUri = contentResolver.insert(RawContacts.CONTENT_URI, values);
		long rawContactId = ContentUris.parseId(rawContactUri);

		values.clear();
		values.put(RawContacts.Data.RAW_CONTACT_ID, rawContactId);
		values.put(RawContacts.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
		values.put(StructuredName.DISPLAY_NAME, firstName + " " + lastName);
		contentResolver.insert(Data.CONTENT_URI, values);
	}
}

Zrzuty ekranu

Kompletny kod źródłowy

Kod źródłowy przykładowej aplikacji można znaleźć na naszym Githubie – HelloContentProviders.

Komentarze (4) Subskrybuj

 

  1. Kasia Lewszuk pisze:

    Świetny artykuł, tego mi brakowało. :) A czy wiesz, może jak wstawić jakies moje dane do kontaktu, tak jak np. zrobił to facebook z profilem? Albo na przykład dodatkowe dane wymyślone przeze mnie, np. model telefonu i żeby były w androidowej książce telefonicznej? :P

  2. Ja w takim wypadku skorzystałbym z tabeli reprezentowanej przez ContactsContract.Data, gdzie do kilkunastu kolumn można dodawać różne informacje a za pomocą pola MimeType określać co to za typ danych.

  3. Paweł pisze:

    Witam, temat wpisu jaki wszystkich pozostałych naprawdę bardzo fajnie opracowane, można wiele ciekawych rzeczy wyciągnąć ;) Mam jednak pytanie a skąd ten magic number „contactsCursor.getString(1)” dlaczego akurat 1?

  4. Kamil pisze:

    Ta magiczna liczba to nic innego jak indeks. Resztę sam sobie dopisz :)

Prześlij komentarz

Zaloguj się lub skorzystaj z profilu:

[rpxlogin redirect="http://www.android4devs.pl" prompt="" style="large"]

Możesz również zostawić komentarz bez rejestracji, korzystając z poniższego formularza:

Musisz być zalogowany aby móc pisać komentarze.