Here is my understand after some 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
The first thing see is VectorDrawableCompat and ResourcesCompat can specific theme
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); in onCreated of Application class
1) For vector image
API >= 21
ContextCompat work wellResourcesCompat work wellAppCompatResources work wellVectorDrawableCompat work wellAPI < 21
ContextCompat crash
ResourcesCompat crash
AppCompatResources work wellVectorDrawableCompat work well2) For normal image
ContextCompat work wellResourcesCompat work wellAppCompatResources work wellVectorDrawableCompat crash
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); in onCreated of Application class
1) For vector image
ContextCompat work wellResourcesCompat work wellAppCompatResources work wellVectorDrawableCompat work well2) For normal image
ContextCompat work wellResourcesCompat work wellAppCompatResources work wellVectorDrawableCompat crash
Looking at the source code of the two methods, they seem very similar. If you don't have vectors, you could probably get away with using either one or the other.
ResourcesCompat.getDrawable() will call Resources#getDrawable(int, theme) on APIs 21 or greater. It also supports Android APIs 4+. It is no more than this:
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);
}
}
Where-in ResourcesCompatApi21 merely calls res.getDrawable(id, theme). This means it will not allow vector drawables to be drawn if the device does not support vector drawables. It will, however, allow you to pass in a theme.
Meanwhile, the code change for AppCompatResources.getDrawable(Context context, int resId) eventually lands to this:
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;
}
So this instance it will attempt to draw the resource if it can, otherwise it looks in the ContextCompat version to get the resource. Then it will even tint it if necessary. However, this method only supports API 7+.
So I guess to decide if you should use either,
Do you have to support API 4, 5, or 6?
ResourcesCompat or ContextCompat.Do you absolutely need to supply a custom Theme?
ResourcesCompat
AppCompatResources
ResourcesCompat, ContextCompat and pretty much any class from support-v4 ending with Compat saves you from writing if (Build.VERSION.SDK_INT >= X) checks everywhere. That's it. For example instead of
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);
}
you can write
final Drawable d = ContextCompat.getDrawable(context, R.drawable.some_image);
The limits described in comments apply, for example
// This line is effectively equivalent to the above.
ResourcesCompat.getDrawable(context.getResources(), R.drawable.some_image, context.getTheme());
does not actually apply the theme attributes before Lollipop (this is said in the documentation). But you don't have to write if checks and your code does not crash on old devices because you're not actually using new APIs there.
AppCompatResources on the other hand will actually help you bring new features to old platforms (support vectors, theme references in color state lists).
Which one should I prefer to another and why?
Use AppCompatResources to get consistent results with the rest of appcompat-v7 library. You'll get:
getColorStateList which can resolve colors with theme attribute references (such as android:alpha="?android:disabledAlpha"),getDrawable which supports inflating vectors on all platforms and these vector drawables also understand theme attribute references (e.g. android:tint="?colorControlNormal"),ContextCompat anyway.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With