91 votes

Les meilleures pratiques pour exposer plusieurs tables à l'aide des fournisseurs de contenus Android

Je suis en train de construire une application où j'ai une table et une table pour les sites. Je veux être en mesure d'accorder à d'autres applications d'accéder à ces données. J'ai quelques questions concernant les meilleures pratiques pour ce genre de problème.

  1. Comment dois-je structurer les classes de base de données? J'ai actuellement des cours pour EventsDbAdapter et VenuesDbAdapter, qui fournissent la logique de l'interrogation de chaque table, tout en ayant un DbManager (s'étend SQLiteOpenHelper) pour la gestion des versions de base de données, création/mise à jour des bases de données donnant accès à la base de données (getWriteable/ReadeableDatabase). Est-ce la solution recommandée, ou serais-je mieux, soit la consolidation de tout ce qui à une classe (c'est à dire. le DbManager) ou de la séparation de tout et de laisser chaque Carte s'étend SQLiteOpenHelper?

  2. Comment dois-je de conception fournisseurs de contenu pour plusieurs tables? L'extension de la précédente question, dois-je utiliser un Fournisseur de Contenu pour l'ensemble de l'application, ou devrais-je créer fournisseurs distincts pour les Événements et les Lieux?

La plupart des exemples que j'ai trouver seuls face à la seule table apps, donc j'apprécierais toute pointeurs ici.

115voto

Opy Points 1346

C'est probablement un peu tard pour vous, mais d'autres peuvent trouver cela utile.

Vous devez d'abord créer plusieurs CONTENT_URIs

public static final Uri CONTENT_URI1 = 
    Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri1");
public static final Uri CONTENT_URI2 = 
    Uri.parse("content://"+ PROVIDER_NAME + "/sampleuri2");

Vous développez votre Comparateur de URI

private static final UriMatcher uriMatcher;
static {
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(PROVIDER_NAME, "sampleuri1", SAMPLE1);
    uriMatcher.addURI(PROVIDER_NAME, "sampleuri1/#", SAMPLE1_ID);      
    uriMatcher.addURI(PROVIDER_NAME, "sampleuri2", SAMPLE2);
    uriMatcher.addURI(PROVIDER_NAME, "sampleuri2/#", SAMPLE2_ID);      
}

Puis créer vos tables

private static final String DATABASE_NAME = "sample.db";
private static final String DATABASE_TABLE1 = "sample1";
private static final String DATABASE_TABLE2 = "sample2";
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_CREATE1 =
    "CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE1 + 
    " (" + _ID1 + " INTEGER PRIMARY KEY AUTOINCREMENT," + 
    "data text, stuff text);";
private static final String DATABASE_CREATE2 =
    "CREATE TABLE IF NOT EXISTS " + DATABASE_TABLE2 + 
    " (" + _ID2 + " INTEGER PRIMARY KEY AUTOINCREMENT," + 
    "data text, stuff text);";

N'oubliez pas d'ajouter le deuxième DATABASE_CREATE de onCreate()

Vous allez utiliser un switch-case bloc de déterminer ce tableau est utilisé. C'est mon insérer le code

@Override
public Uri insert(Uri uri, ContentValues values) {
    Uri _uri = null;
    switch (uriMatcher.match(uri)){
    case SAMPLE1:
        long _ID1 = db.insert(DATABASE_TABLE1, "", values);
        //---if added successfully---
        if (_ID1 > 0) {
            _uri = ContentUris.withAppendedId(CONTENT_URI1, _ID1);
            getContext().getContentResolver().notifyChange(_uri, null);    
        }
        break;
    case SAMPLE2:
        long _ID2 = db.insert(DATABASE_TABLE2, "", values);
        //---if added successfully---
        if (_ID2 > 0) {
            _uri = ContentUris.withAppendedId(CONTENT_URI2, _ID2);
            getContext().getContentResolver().notifyChange(_uri, null);    
        }
        break;
    default: throw new SQLException("Failed to insert row into " + uri);
    }
    return _uri;                
}

Vous aurez besoin de diviser l' delete, update, getType, etc. Partout où votre fournisseur d'appels pour DATABASE_TABLE ou CONTENT_URI, vous allez ajouter un cas et ont DATABASE_TABLE1 ou CONTENT_URI1 dans l'un et n ° 2 dans la prochaine et ainsi de suite pour autant que vous le souhaitez.

10voto

Marloke Points 1028

Je recommande de vérifier le code source d'Android 2.x ContactProvider. (Qui peut être trouvé en ligne). Ils ont la poignée de la croix de la table de requêtes par des services spécialisés de points de vue que vous, puis d'exécuter des requêtes sur l'extrémité arrière. Sur l'extrémité avant, ils sont accessibles à l'appelant par l'intermédiaire de divers différents Uri, grâce à un seul fournisseur de contenu. Vous voudrez aussi de fournir une classe ou deux pour la tenue des constantes pour votre table de noms de champ et les chaînes URI. Ces classes pourraient être fournis, soit de l'API de l'inclure ou comme une goutte d'eau dans la classe, et il sera beaucoup plus facile pour les consommateurs de l'application à utiliser.

C'est un peu complexe, de sorte que vous pourriez également vouloir vérifier comment le calendrier pour avoir une idée de ce que vous faites et n'ont pas besoin.

Vous devriez seulement besoin d'un seul adaptateur DB et un seul fournisseur de Contenu par base de données (pas par table) pour faire le gros du travail, mais vous pouvez utiliser plusieurs adaptateurs/fournisseurs si vous le voulez vraiment. Il rend juste les choses un peu plus compliquées.

7voto

Timo Ohr Points 5550

Un ContentProvider peut servir à de multiples tables, mais ils devraient être quelque peu liés. Il fera une différence si vous avez l'intention de synchroniser vos fournisseurs. Si vous voulez séparer les synchronisations pour, disons, les Contacts, la Messagerie ou le Calendrier, vous aurez besoin de différents fournisseurs pour chacun d'eux, même s'ils finissent par être dans la même base de données ou sont synchronisés avec le même service, en raison de la Synchronisation des Adaptateurs sont directement liés à un fournisseur particulier.

Aussi loin que je peux dire, vous ne pouvez utiliser qu'un seul SQLiteOpenHelper par base de données, car il stocke ses des méta-informations dans une table dans la base de données. Donc, si votre ContentProviders accéder à la même base de données, vous aurez à part l'aide somewhow.

7voto

PeteH Points 470

Remarque: C'est une clarification et/ou de modification de la réponse de fournir par Opia.

Cette approche permet de subdiviser chacune des insert, delete, update, et getType méthodes avec les instructions switch pour gérer chacun de vos tables. Vous utiliserez un CAS à identifier chaque table (ou uri) pour la référence. Chaque CAS correspond à un de vos tables ou de URI. E. g., TABLE1 ou URI1 est sélectionné dans le CAS n ° 1, etc. pour toutes les tables de votre application utilise.

Voici un exemple de l'approche. C'est pour la méthode d'insertion. Il a mis en œuvre un peu différemment de Opia mais remplit la même fonction. Vous pouvez sélectionner le style que vous préférez. Je voulais aussi assurez-vous d'insérer renvoie une valeur, même si l'insertion de la table échoue. Dans ce cas, elle renvoie un -1.

  @Override
  public Uri insert(Uri uri, ContentValues values) {
    int uriType = sURIMatcher.match(uri);
    SQLiteDatabase sqlDB; 

    long id = 0;
    switch (uriType){ 
        case TABLE1: 
            sqlDB = Table1Database.getWritableDatabase();
            id = sqlDB.insert(Table1.TABLE_NAME, null, values); 
            getContext().getContentResolver().notifyChange(uri, null);
            return Uri.parse(BASE_PATH1 + "/" + id);
        case TABLE2: 
            sqlDB = Table2Database.getWritableDatabase();
            id = sqlDB.insert(Table2.TABLE_NAME, null, values); 
            getContext().getContentResolver().notifyChange(uri, null);
            return Uri.parse(BASE_PATH2 + "/" + id);
        default: 
            throw new SQLException("Failed to insert row into " + uri); 
            return -1;
    }       
  }  // [END insert]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X