ResourcesCompat.getDrawable() vs AppCompatResources.getDrawable()
Here is my understanding after some testing:
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 I see is VectorDrawableCompat
and ResourcesCompat
can specify a theme.
I) Without using
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
in onCreated
of the Application class
1) For vector images
API >= 21
ContextCompat
works wellResourcesCompat
works wellAppCompatResources
works wellVectorDrawableCompat
works wellAPI < 21
ContextCompat
crashResourcesCompat
crashAppCompatResources
works wellVectorDrawableCompat
works well
2) For normal image
- In all API levels
ContextCompat
works wellResourcesCompat
works wellAppCompatResources
works wellVectorDrawableCompat
crash
II) Using
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
in onCreated
of the Application class
1) For vector images
- In all API levels
ContextCompat
works wellResourcesCompat
works wellAppCompatResources
works wellVectorDrawableCompat
works well
2) For normal images
- In all API levels
ContextCompat
works wellResourcesCompat
works wellAppCompatResources
works 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?
- Yes: No choice but to use
ResourcesCompat
orContextCompat
. - No: Keep going to #2.
- Yes: No choice but to use
Do you absolutely need to supply a custom Theme?
- Yes: No choice but to use
ResourcesCompat
- No: Use
AppCompatResources
- Yes: No choice but to use