Dans ce tutoriel, nous allons parler des ContentProviders et expliquer à l’aide d’un exemple comment les utiliser et comment en créer pour vos applications.

Qu’est-ce qu’un ContentProvider ?

Un contentProvider sert à stocker et récupérer des données et ainsi les rendre accessibles à toutes les applications. C’est le moyen le plus connu de partager des données entres différentes applications. Par exemple, il existe un Content Provider gérant les Contacts d’un téléphone.

Android propose plusieurs ContentProviders basiques (audio, vidéo, images, informations sur les contacts…). Un contentProvider se compose d’une :

  • Uri
  • Méthodes (Insert, Update, Delete, Query).

Le chemin d’accès vers un ContentProvider se présente toujours sous forme d’une URI. Par exemple :

  • A : Un préfixe standard, il sert à indiquer que les données sont contrôlées par un ContentProvider.
  • B : L’autorité qui contrôle cette URI. Elle identifie le ContentProvider responsable de cette URI.
  • C : Permet au ContentProvider de savoir quelle donnée est requêtée par l’url. Ce segment est optionnel. Un content provider peut exposer plusieurs données (ici les trains) mais on pourrait avoir par exemple les voitures, donc ce ContentProvider pourra gérer deux types de données.
  • D : L’id de la donnée qu’on souhaite récupérer. (optionnel)

Comment créer un ContentProvider ?

Pour créer un ContentProvider, vous devez :

  • Mettre en place un systéme pour stocker vos données (les contents providers utilisent généralement le SQLite, la classe SQLiteOpenHelper vous facilite la création de votre base).
  • Etendre la classe ContentProvider.
  • Déclarer votre Content Provider dans le manifest (AndroidManifest.xml).
  • Un Content Provider doit surcharger les 6 méthodes suivantes :
    • query() : Cette méthode retourne un objet Cursor sur lequel vous pouvez itérer pour récupérer les données.
    • insert() : Cette méthode est utilisé pour rajouter des données à notre ContentProvider.
    • update() : Cette méthode est utilisé pour mettre à jour une données déjà existante dans notre Content Provider.
    • delete() : Cette méthode permet de supprimer une données du Content Provider.
    • getType() : Retourne le type MIME des données contenues dans le Content Provider.
    • onCreate() : Appeler afin d’initialiser le Content Provider

Exemple

Nous allons étudier un exemple complet de création et l’utilisation d’un ContentProvider.
Pour commencer, nous allons créer un projet :

  • Nom du projet : Content Provider Exemple
  • SDK version : 2.3.3
  • Nom de l’application : ContentProviderExemple
  • Nom du package : com.tutos.android.content.provider
  • Activité : ContentProviderExempleActivity

Notre ContentProvider servira à gérer une liste de cours, chaque cours possédant un id, un nom et une description.

Pour commencer, nous allons créer la classe qui contiendra le nom des colonnes de notre table SQLite.

public class SharedInformation {

	public SharedInformation() {
	}

	public static final class Cours implements BaseColumns {
		
		private Cours() {}

		public static final String COURS_ID = "COURS";
		public static final String COURS_NAME = "COURS_NAME";
		public static final String COURS_DESC = "COURS_DESC";
	}
}

Cette classe est très simple, elle contient simplement l’identifiant des 3 colonnes. Elle doit absolument implémenter BaseColumns.

Maintenant, nous allons créer une classe qui gérera notre base de données. Elle doit hériter de la classe SQLiteOpenHelper, pour nous faciliter la création de notre base de données.
Cette classe se nommera : AndroidProvider

// URI de notre content provider, elle sera utilisé pour accéder au ContentProvider 
public static final Uri CONTENT_URI = Uri
	.parse("content://com.tutos.android.content.provider.tutosandroidprovider");

// Nom de notre base de données 
	public static final String CONTENT_PROVIDER_DB_NAME = "tutosandroid.db";
// Version de notre base de données 
	public static final int CONTENT_PROVIDER_DB_VERSION = 1;
// Nom de la table de notre base 
	public static final String CONTENT_PROVIDER_TABLE_NAME = "cours";
// Le Mime de notre content provider, la premiére partie est toujours identique 
	public static final String CONTENT_PROVIDER_MIME = "vnd.android.cursor.item/vnd.tutos.android.content.provider.cours";

	
// Notre DatabaseHelper 
private static class DatabaseHelper extends SQLiteOpenHelper {

	// Création à partir du Context, du Nom de la table et du numéro de version 
	DatabaseHelper(Context context) {
super(context,TutosAndroidProvider.CONTENT_PROVIDER_DB_NAME, null, TutosAndroidProvider.CONTENT_PROVIDER_DB_VERSION);
	}

	// Création des tables 
	@Override
	public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME + " (" + Cours.COURS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + Cours.COURS_NAME + " VARCHAR(255)," + Cours.COURS_DESC + " VARCHAR(255)" + ");");
	}

	// Cette méthode sert à gérer la montée de version de notre base 
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME);
		onCreate(db);
	}
}

Cette classe comprend :

  • La déclaration de l’uri de notre ContentProvider, vous remarquez bien le format « content:// »
  • Le nom de notre base de données
  • La version de la base
  • Le nom de notre table
  • Le Mime correspondant à notre ContentProvider
  • Une méthode onCreate, qui sert à créer nos tables. Il s’agit d’une Requête SQL classique.
  • Une méthode onUpgrade qui permet de monter de version dans une application.

Maintenant nous allons surcharger les méthodes :

onCreate (Celle du ContentProvider) qui permet d’initialiser notre DatabaseHelper dans la classe représentant notre ContentProvider.

	@Override
	public boolean onCreate() {
			dbHelper = new DatabaseHelper(getContext());
			return true;
	}

geType : qui retourne le type de notre ContentProvider,ce qui correspond tout simplement à notre MIME

	@Override
	public String getType(Uri uri) {
			return TutosAndroidProvider.CONTENT_PROVIDER_MIME;
}
	

getId : Cette méthode nous permet de récupérer l’id de notre Uri

private long getId(Uri uri) {
		String lastPathSegment = uri.getLastPathSegment();
		if (lastPathSegment != null) {
			try {
				return Long.parseLong(lastPathSegment);
			} catch (NumberFormatException e) {
				Log.e("TutosAndroidProvider", "Number Format Exception : " + e);
			}
		}
		return -1;
}

insert : Cette méthode sert à rajouter une valeur à notre ContentProvider.

/**
* Insert a value
 */
@Override
public Uri insert(Uri uri, ContentValues values) {
	SQLiteDatabase db = dbHelper.getWritableDatabase();
	try {
long id = db.insertOrThrow(			 TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME, null, values);
			
if (id == -1) {
			throw new RuntimeException(String.format(
			"%s : Failed to insert [%s] for unknown reasons.","TutosAndroidProvider", values, uri));
		} else {
			return ContentUris.withAppendedId(uri, id);
		}
		
} finally {
			db.close();
		}
	}
  • On commence par récupérer une instance de la base de données en mode ecriture.
  • Puis on insère nos données à l’aide de la méthode insertOrThrow qui retourne l’id de l’insertion dans la base et -1 en cas d’échec de l’insertion.
  • Sans oublier de fermer la connexion à la base de données quelques soit le resultat.

update : Cette méthode permet de mettre à jour une valeur déja existante dans la base.

/**
* update a value
 */
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
	long id = getId(uri);
	SQLiteDatabase db = dbHelper.getWritableDatabase();
	
try {
		if (id < 0)
return db.update( TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME,values, selection, selectionArgs);
		else
			return db.update(								TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME,
			values, Cours.COURS_ID + "=" + id, null);
		} finally {
			db.close();
		}
	}
  • On récupérer l’id de l’élément
  • Si l’id est supérieur à 0, on met à jour l’élément
  • Sinon on essaye à mettre à jour l’élement par sa valeur.
  • Sans oublier de fermer la base à la fin
  • delete : Cette méthode sert à suprimer un élément de notre Content provider.

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
    		long id = getId(uri);
    		SQLiteDatabase db = dbHelper.getWritableDatabase();
    		try {
    			if (id < 0)
    				return db.delete(
    						TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME,
    						selection, selectionArgs);
    			else
    				return db.delete(
    						TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME,
    						Cours.COURS_ID + "=" + id, selectionArgs);
    		} finally {
    			db.close();
    		}
    }
    

    Même fonctionnement que pour le “Update”

    query : Cette méthode sert à récupérer une donnée présente dans notre ContentProvider.

    @Override
    	public Cursor query(Uri uri, String[] projection, String selection,
    			String[] selectionArgs, String sortOrder) {
    		long id = getId(uri);
    		SQLiteDatabase db = dbHelper.getReadableDatabase();
    		if (id < 0) {
    			return 	db.query(TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME,
    	projection, selection, selectionArgs, null, null,
    		sortOrder);
    		} else {
    			return 		db.query(TutosAndroidProvider.CONTENT_PROVIDER_TABLE_NAME,
    		projection, Cours.COURS_ID + "=" + id, null, null, null,
    		null);
    		}
    	}
    

    Création d’une classe de test

    Nous allons modifier ContentProviderExempleActivity pour tester notre contentProvider

    public class ContentProviderExempleActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main);
    		insertRecords();
    		displayContentProvider();
    	}
    
    	private void displayContentProvider() {
    		String columns[] = new String[] { Cours.COURS_ID, Cours.COURS_NAME, Cours.COURS_DESC };
    		Uri mContacts = TutosAndroidProvider.CONTENT_URI;
    		Cursor cur = managedQuery(mContacts, columns, null, null, null);
    		Toast.makeText(ContentProviderExempleActivity.this, cur.getCount() + "",
    				Toast.LENGTH_LONG).show();
    
    		if (cur.moveToFirst()) {
    			String name = null;
    			do {
    				name = cur.getString(cur.getColumnIndex(Cours.COURS_ID)) + " " +
    						cur.getString(cur.getColumnIndex(Cours.COURS_NAME)) + " " + 
    						cur.getString(cur.getColumnIndex(Cours.COURS_DESC));
    				Toast.makeText(this, name + " ", Toast.LENGTH_LONG).show();
    			} while (cur.moveToNext());
    		}
    
    	}
    
    	private void insertRecords() {
    		ContentValues contact = new ContentValues();
    		contact.put(Cours.COURS_NAME, "Android");
    		contact.put(Cours.COURS_DESC, "Introduction à la programmation sous Android");
    		getContentResolver().insert(TutosAndroidProvider.CONTENT_URI, contact);
    
    		contact.clear();
    		contact.put(Cours.COURS_NAME, "Java");
    		contact.put(Cours.COURS_DESC, "Introduction à la programmation Java");
    		getContentResolver().insert(TutosAndroidProvider.CONTENT_URI, contact);
    
    		contact.clear();
    		contact.put(Cours.COURS_NAME, "Iphone");
    		contact.put(Cours.COURS_DESC, "Introduction à l'objectif C");
    		getContentResolver().insert(TutosAndroidProvider.CONTENT_URI, contact);
    	}
    }
    

    Cette classe posséde deux méthodes :
    - InsertRecords
    On crée un ContentValue, puis on appelle la méthode getContentResolver pour récupérer une instance de ContentProvider, puis on appelle la méthode insert avec l’uri et les valeurs à insérer.
    - DisplayContentProvider
    Cette méthode sert à récupérer tous les éléments contenus dans notre ContentProvider
    Puis on parcours le Cursor et on affiche chaque élément

    AndroidManifest.xml

    Pour l’instant cette exemple ne fonctionne pas, car il manque la partie configuration et déclaration de notre provider, dans l’AndroidManifest

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="ccom.tutos.android.content.provider"
          android:versionCode="1"
          android:versionName="1.0">
        <uses-sdk android:minSdkVersion="10" />
    
        <application android:icon="@drawable/icon" android:label="@string/app_name">
            <activity android:name="com.tutos.android.content.provider.ContentProviderExempleActivity"
                      android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
    				<category android:name="android.intent.category.DEFAULT" />
    				<data android:mimeType="vnd.android.cursor.item/vnd.tutos.android.content.provider.cours" />
                </intent-filter>
            </activity>
            
            <provider android:name="com.tutos.android.content.provider.TutosAndroidProvider"
    			android:authorities="com.tutos.android.content.provider.tutosandroidprovider" />
    
        </application>
    </manifest>
    

    Dans notre activité, on déclare une balise data dans l’intent-filter avec comme valeur le MimeType de notre content provider
    Puis on déclare une balise provider, avec comme valeur, le chemin vers la classe du provider et l’authorité définie dans le provider

    Conclusion

    Voila cet article s’arrête ici, en espérant qu’il vous a aidé à comprendre comment fonctionne les contents providers.
    Vous allez trouvé ici les sources du projet.
    N’hesitez pas à me poser des questions si des parties ne semblent pas claires.

Categories: Tutoriels

15 Responses so far.


  1. abdelaziz1991 dit :

    merci tes tutos sont genials et tu me donnes envie de poursuivre dans android car je suis un débutant

  2. tux dit :

    Bravo pour le plagiat!

Leave a Reply


Notifiez-moi des commentaires à venir via email. Vous pouvez aussi vous abonner sans commenter.