web-dev-qa-db-fra.com

ResourcesCompat.getDrawable () vs AppCompatResources.getDrawable ()

Je suis un peu confus avec ces deux API.

ResourcesCompat.getDrawable (Ressources res, int id, Resources.Theme theme)

Renvoie un objet dessinable associé à un ID de ressource particulier et stylisé pour le thème spécifié. Différents types d'objets seront retournés en fonction de la ressource sous-jacente - par exemple, une couleur unie, une image PNG, une image évolutive, etc.

Avant le niveau 21 de l'API, le thème ne sera pas appliqué et cette méthode appelle simplement via getDrawable (int).

AppCompatResources.getDrawable (Contexte contextuel, int resId)

Renvoie un objet dessinable associé à un ID de ressource particulier.

Cette méthode prend en charge l'inflation des ressources vectorielles et vectorielles animées sur les appareils où le support de la plateforme n'est pas disponible.

Question

  1. Quelle est la différence significative entre ces deux classes (outre l'inflation vectorielle )?
  2. Laquelle devrais-je préférer à une autre et pourquoi?
24
azizbekian

En regardant le code source des deux méthodes, elles semblent très similaires. Si vous n'avez pas de vecteurs, vous pourriez probablement vous en sortir en utilisant l'un ou l'autre.

ResourcesCompat.getDrawable() appellera Resources#getDrawable(int, theme) sur les API 21 ou plus. Il prend également en charge Android API 4+. Ce n'est pas plus que cela:

public Drawable getDrawable(Resources res, int id, Theme theme)
        throws NotFoundException {
    final int version = Build.VERSION.SDK_INT;
    if (version >= 21) {
        return ResourcesCompatApi21.getDrawable(res, id, theme);
    } else {
        return res.getDrawable(id);
    }
}

Où-in ResourcesCompatApi21 Appelle simplement res.getDrawable(id, theme). Cela signifie qu'il ne permettra pas de dessiner des dessinables vectoriels si le périphérique ne prend pas en charge les dessinables vectoriels. Il vous permettra cependant de passer dans un thème.

Pendant ce temps, le changement de code pour AppCompatResources.getDrawable(Context context, int resId) finit par arriver à ceci:

    Drawable getDrawable(@NonNull Context context, @DrawableRes int resId, boolean failIfNotKnown) {
      checkVectorDrawableSetup(context);

      Drawable drawable = loadDrawableFromDelegates(context, resId);
      if (drawable == null) {
        drawable = createDrawableIfNeeded(context, resId);
      }
      if (drawable == null) {
        drawable = ContextCompat.getDrawable(context, resId);
      }

      if (drawable != null) {
        // Tint it if needed
        drawable = tintDrawable(context, resId, failIfNotKnown, drawable);
      }
      if (drawable != null) {
        // See if we need to 'fix' the drawable
        DrawableUtils.fixDrawable(drawable);
      }
    return drawable;
   }

Ainsi, cette instance tentera de dessiner la ressource si elle le peut, sinon elle regarde dans la version ContextCompat pour obtenir la ressource. Ensuite, il le teint même si nécessaire. Cependant, cette méthode ne prend en charge que l'API 7+.

Donc, je suppose que pour décider si vous devez utiliser l'un ou l'autre,

  1. Devez-vous prendre en charge les API 4, 5 ou 6?

    • Oui: pas d'autre choix que d'utiliser ResourcesCompat ou ContextCompat.
    • Non: Continuez avec le # 2.
  2. Avez-vous absolument besoin de fournir un thème personnalisé?

    • Oui: pas d'autre choix que d'utiliser ResourcesCompat
    • Non: utilisez AppCompatResources
24
DeeV

Voici ma compréhension après un test

ContextCompat.getDrawable(@NonNull Context context, @DrawableRes int resId)

ResourcesCompat.getDrawable(@NonNull Resources res, @DrawableRes int id, @Nullable Theme theme)

AppCompatResources.getDrawable(@NonNull Context context, @DrawableRes int resId)

VectorDrawableCompat.create(@NonNull Resources res, @DrawableRes int resId, @Nullable Theme theme

La première chose à voir est VectorDrawableCompat et ResourcesCompat peut un thème spécifique

I) Sans utiliser

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); dans onCreated de la classe Application

1) Pour l'image vectorielle

  • API> = 21

    • ContextCompat fonctionne bien
    • ResourcesCompat fonctionne bien
    • AppCompatResources fonctionne bien
    • VectorDrawableCompat fonctionne bien
  • API <21

    • ContextCompatcrash
    • ResourcesCompatcrash
    • AppCompatResources fonctionne bien
    • VectorDrawableCompat fonctionne bien

2) Pour une image normale

  • À tous les niveaux
    • ContextCompat fonctionne bien
    • ResourcesCompat fonctionne bien
    • AppCompatResources fonctionne bien
    • VectorDrawableCompatcrash

II) Utilisation

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); dans onCreated de la classe Application

1) Pour l'image vectorielle

  • À tous les niveaux
    • ContextCompat fonctionne bien
    • ResourcesCompat fonctionne bien
    • AppCompatResources fonctionne bien
    • VectorDrawableCompat fonctionne bien

2) Pour une image normale

  • À tous les niveaux
    • ContextCompat fonctionne bien
    • ResourcesCompat fonctionne bien
    • AppCompatResources fonctionne bien
    • VectorDrawableCompatcrash
33
Phan Van Linh

ContextCompat

ResourcesCompat, ContextCompat et à peu près n'importe quelle classe de support-v4 se terminant par Compat vous évite d'écrire des vérifications if (Build.VERSION.SDK_INT >= X) partout. C'est ça. Par exemple au lieu de

final Drawable d;
if (Build.VERSION.SDK_INT < 21) {
    // Old method, drawables cannot contain theme references.
    d = context.getResources().getDrawable(R.drawable.some_image);
} else {
    // Drawables on API 21 can contain theme attribute references.
    // Context#getDrawable only exists since API 21.
    d = context.getDrawable(R.drawable.some_image);
}

tu peux écrire

final Drawable d = ContextCompat.getDrawable(context, R.drawable.some_image);

Les limites décrites dans les commentaires s'appliquent, par exemple

// This line is effectively equivalent to the above.
ResourcesCompat.getDrawable(context.getResources(), R.drawable.some_image, context.getTheme());

n'applique pas réellement les attributs de thème avant Lollipop (cela est dit dans la documentation). Mais vous n'avez pas à écrire si les vérifications et votre code ne plantent pas sur les anciens appareils parce que vous n'utilisez pas réellement de nouvelles API là-bas.

AppCompatResources

AppCompatResources d'autre part, vous aidera en fait à apporter de nouvelles fonctionnalités aux anciennes plates-formes (vecteurs de support, références de thème dans les listes d'état des couleurs).

Laquelle devrais-je préférer à une autre et pourquoi?

Utilisez AppCompatResources pour obtenir des résultats cohérents avec le reste de la bibliothèque appcompat-v7. Tu auras:

  • getColorStateList qui peut résoudre les couleurs avec des références d'attribut de thème (comme Android:alpha="?android:disabledAlpha"),
  • getDrawable qui prend en charge le gonflement des vecteurs sur toutes les plates-formes et ces drawables vectoriels comprennent également les références d'attribut de thème (par exemple Android:tint="?colorControlNormal"),
  • les tirages et les couleurs appcompat-v7 comme les coches ou les boutons radio auront les couleurs appropriées définies par le thème de contexte fourni,
  • si ce qui précède ne s'applique pas, il revient quand même à ContextCompat.
8
Eugen Pechanec