web-dev-qa-db-fra.com

en utilisant ContentProviderClient vs ContentResolver pour accéder au fournisseur de contenu

Le documentation sur Android fournisseurs de conten décrit l'utilisation d'un ContentResolver, obtenu à partir de getContentResolver(), pour accéder au contenu.

Cependant, il existe également un ContentProviderClient, qui peut être obtenu à partir de getContentResolver().acquireContentProviderClient(authority). Il semble fournir plus ou moins les mêmes méthodes disponibles dans le ContentResolver pour accéder au contenu du fournisseur.

Quand dois-je utiliser un ContentProviderClient au lieu d'utiliser simplement le ContentResolver directement? Quels sont les bénéfices?

63
Robert Tupelo-Schneck

Votre Android possède de nombreuses bases de données, chacune étant identifiée par une autorité de contenu unique. Il s'agit de la partie équivalente du "nom de domaine" dans le contenu: // uri - tout avant la première barre oblique .

ContentResolver stocke les données fournissant un mappage de String contentAuthority à ContentProvider. Lorsque vous appelez ContentResolver.query() ou update() ou quoi d'autre, l'URI est analysé séparément dans ses composants, la chaîne contentAuthority est identifiée et contentResolver doit rechercher dans cette carte une chaîne correspondante, et dirigez la requête vers le bon fournisseur. Cette recherche coûteuse se produit lors de chaque appel, car l'URI peut être différent d'un appel à l'autre, avec une autorité de contenu différente également. De plus, la configuration et la suppression d'une connexion à ce fournisseur spécifique peuvent entraîner des coûts. Elle ne peut pas être réutilisée pour les appels. Je ne suis pas sûr de la surcharge impliquée là-bas, c'est un code de niveau OS assez profond.

En revanche, lorsque vous appelez acquireContentProviderClient(authority), ce "de quel fournisseur ai-je besoin?" la recherche est effectuée une fois et vous obtenez un ContentProviderClient qui est essentiellement un lien direct vers le ContentProvider. (Il y a un peu de colle entre vous et le fournisseur qui implique la communication entre les threads et le verrouillage simultané). Cependant, lorsque vous utilisez ContentProviderClient, vous parlerez directement au fournisseur pour l'autorité que vous avez demandée. Cela élimine le gaspillage de constamment recalculer "quel fournisseur est-ce que je veux?"

REMARQUE: Per documentation documentation d'acquisitionContentProviderClient () : Si vous obtenez un ContentProviderClient, "L'appelant doit indiquer qu'il sont faites avec le fournisseur en appelant ContentProviderClient.release () qui permettra au système de libérer le fournisseur s'il détermine qu'il n'y a pas d'autre raison de le garder actif. " Donc, essentiellement , laisser un client périmé ouvert forcera le fournisseur à continuer à fonctionner en tant que service en arrière-plan. Alors, n'oubliez pas de nettoyer!

Résumé:

Nombreux appels à différentes autorités de contenu: Utilisez ContentResolver.

Appels répétés à la même autorité: Obtenez et utilisez ContentProviderClient. N'oubliez pas de le libérer () lorsque vous avez terminé.

90
jcwenger

Ok, mais sachez que cela ne fonctionne que lorsque ContentProvider exécuté dans le même processus que Activity.

Remarque de la documentation de la méthode getLocalContentProvider():

Si ContentProvider s'exécute dans un processus différent, null sera renvoyé. Cela peut être utilisé si vous savez que vous exécutez le même processus qu'un fournisseur et que vous souhaitez accéder directement à ses détails d'implémentation.

7
Jokii

Je pense que l'autre différence d'importation est que ContentProviderClient peut être casté dans votre objet fournisseur personnalisé et accéder à une autre méthode en plus de CRUD.

ContentProvider cp = getContentResolver().acquireContentProviderClient(mCurUri).getLocalContentProvider();
yourProvider fld = (yourProvider)cp;
fld.query(...);           // you can query as ContentResolver
fld.addFolder(newFolder); // also can invoke the extend method of your custom ContentProvider
4
guangmao.yu

J'ai trouvé la différence suivante: j'ai écrit mon propre fournisseur de contenu personnalisé dans l'application A. J'ai écrit un widget d'écran d'accueil dans l'application B. Lorsque j'ai essayé d'accéder au ContentProvider de l'application A via un ContentResolver à partir de mon widget, j'ai obtenu un "échec de recherche de fournisseur" info "erreur. Au lieu de cela, je devrais acquérir un ContentProviderClient via le ContentResolver et interroger le ContentProviderClient, cela fonctionnerait. Je ne devais rien changer d'autre, utiliser uniquement ContentProviderClient au lieu de ContentResolver. Je n'ai aucune explication réelle de ce comportement et je n'ai trouvé aucune information sur Internet pour expliquer pourquoi il en est ainsi. Je ne sais pas, s'il s'agit d'une bizarrerie spéciale de widgets, car je ne l'ai pas essayé à partir d'une activité dans l'application B (l'application B est un simple widget, sans activité).

2
mrd

L'une des utilisations de ContentProviderClient est utile pour accéder à certaines des méthodes de ContentProvider lors des tests. Par exemple, j'utilise la méthode shutdown () dans les tests unitaires pour éviter plusieurs tests instanciant plusieurs fournisseurs de contenu.

Implémentez ContentProvider#shutdown() comme ceci:

@Override
public void shutdown() {
    openHelper.close();
    super.shutdown();
}

Et à la fin de la méthode de test, appelez shutdown() à l'aide de ContentProviderClient pour nettoyer le test afin que d'autres tests puissent utiliser le fournisseur de contenu:

getContext()
       .getContentResolver()
       .acquireContentProviderClient(URI)
       .getLocalContentProvider()
       .shutdown();
0