ResourcesCompat.getDrawable() 对比 AppCompatResources.getDrawable()
ResourcesCompat.getDrawable() vs AppCompatResources.getDrawable()
我对这两个 API 有点困惑。
ResourcesCompat.getDrawable(Resources res, int id, Resources.Theme theme)
Return a drawable object associated with a particular resource ID and styled for the specified theme. Various types of objects will be returned depending on the underlying resource -- for example, a solid color, PNG image, scalable image, etc.
Prior to API level 21, the theme will not be applied and this method simply calls through to getDrawable(int).
AppCompatResources.getDrawable(Context context, int resId)
Return a drawable object associated with a particular resource ID.
This method supports inflation of vector and animated-vector resources on devices where platform support is not available.
问题
- 这两者有什么显着区别类
(除了 向量 inflation)?
- 我应该更喜欢哪一个,为什么?
看这两个方法的源码,好像很相似。如果你没有向量,你可能会使用其中一个或另一个来逃避。
ResourcesCompat.getDrawable()
将在 API 21 岁或更大时调用 Resources#getDrawable(int, theme)
。它还支持 Android APIs 4+。无非是这样:
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
仅调用 res.getDrawable(id, theme)
。这意味着如果设备不支持矢量可绘制对象,它将不允许 允许绘制矢量可绘制对象。但是,它将允许您传递主题。
与此同时,AppCompatResources.getDrawable(Context context, int resId)
的代码更改最终会变成这样:
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;
}
所以这个实例如果可以的话它将尝试绘制资源,否则它会在 ContextCompat
版本中查找以获取资源。然后它甚至会在必要时对其进行着色。不过这个方法只支持API7+.
所以我想决定你是否应该使用其中之一,
您必须支持 API 4、5 或 6 吗?
- 是:别无选择,只能使用
ResourcesCompat
或 ContextCompat
。
- 否:继续#2。
您绝对需要提供自定义主题吗?
- 是:别无选择,只能使用
ResourcesCompat
- 否:使用
AppCompatResources
上下文兼容性
ResourcesCompat
、ContextCompat
和几乎任何来自 support-v4 以 Compat
结尾的 class 都可以避免在任何地方编写 if (Build.VERSION.SDK_INT >= X)
检查。而已。例如,而不是
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);
}
你可以写
final Drawable d = ContextCompat.getDrawable(context, R.drawable.some_image);
注释中描述的限制适用,例如
// This line is effectively equivalent to the above.
ResourcesCompat.getDrawable(context.getResources(), R.drawable.some_image, context.getTheme());
实际上并没有在 Lollipop 之前应用主题属性(这在文档中有说明)。但是您不必编写 if 检查并且您的代码不会在旧设备上崩溃,因为您实际上并没有在那里使用新的 API。
AppCompatResources
另一方面,AppCompatResources
实际上会帮助您为旧平台带来新功能(支持向量、颜色状态列表中的主题参考)。
Which one should I prefer to another and why?
使用 AppCompatResources
获得与 appcompat-v7 库的其余部分一致的结果。你会得到:
getColorStateList
可以用主题属性引用解析颜色(比如android:alpha="?android:disabledAlpha"
),
getDrawable
支持所有平台上的膨胀矢量,这些矢量可绘制对象也理解主题属性引用(例如 android:tint="?colorControlNormal"
),
- appcompat-v7 可绘制对象和颜色(如复选标记或单选按钮)将具有由提供的上下文主题定义的正确颜色,
- 如果以上不适用,则无论如何都会退回到
ContextCompat
。
这是我测试后的理解
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
首先看到的是VectorDrawableCompat
和ResourcesCompat
可以具体主题
I) 不使用
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
在 onCreated
中 class
1) 对于矢量图
API >= 21
ContextCompat
工作顺利
ResourcesCompat
工作顺利
AppCompatResources
工作顺利
VectorDrawableCompat
工作顺利
API < 21
ContextCompat
崩溃
ResourcesCompat
崩溃
AppCompatResources
工作顺利
VectorDrawableCompat
工作顺利
2) 对于普通图像
- 在所有级别
ContextCompat
工作顺利
ResourcesCompat
工作顺利
AppCompatResources
工作顺利
VectorDrawableCompat
崩溃
II) 使用
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
在 onCreated
中 class
1) 对于矢量图
- 在所有级别
ContextCompat
工作顺利
ResourcesCompat
工作顺利
AppCompatResources
工作顺利
VectorDrawableCompat
工作顺利
2) 对于普通图像
- 在所有级别
ContextCompat
工作顺利
ResourcesCompat
工作顺利
AppCompatResources
工作顺利
VectorDrawableCompat
崩溃
API 19+ 解决方法
package com.example;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
/**
*
*/
public class AppDrawableCompat {
public static Drawable getDrawable(@NonNull Context context, @DrawableRes int resId) {
try {
return AppCompatResources.getDrawable(context, resId);
} catch (Resources.NotFoundException e1) {
try {
return ContextCompat.getDrawable(context, resId);
} catch (Resources.NotFoundException e2) {
return VectorDrawableCompat.create(context.getResources(), resId, context.getTheme());
}
}
}
@Nullable
public static Drawable findDrawable (@NonNull Context context, @DrawableRes int resId) {
try {
return getDrawable(context, resId);
} catch (Resources.NotFoundException e) {
return null;
}
}
public static void setViewBackgroundDrawable(@NonNull View view, @NonNull Context context, @DrawableRes int resId) {
Drawable drawable = findDrawable(context, resId);
if (drawable != null) {
view.setBackground(drawable);
}
}
}
使用示例 (MainActivity#onCreate)
ImageView icon = findViewById(R.id.icon);
AppDrawableCompat.setViewBackgroundDrawable(icon, this, R.drawable.bg_icon);
我对这两个 API 有点困惑。
ResourcesCompat.getDrawable(Resources res, int id, Resources.Theme theme)
Return a drawable object associated with a particular resource ID and styled for the specified theme. Various types of objects will be returned depending on the underlying resource -- for example, a solid color, PNG image, scalable image, etc.
Prior to API level 21, the theme will not be applied and this method simply calls through to getDrawable(int).
AppCompatResources.getDrawable(Context context, int resId)
Return a drawable object associated with a particular resource ID.
This method supports inflation of vector and animated-vector resources on devices where platform support is not available.
问题
- 这两者有什么显着区别类 (除了 向量 inflation)?
- 我应该更喜欢哪一个,为什么?
看这两个方法的源码,好像很相似。如果你没有向量,你可能会使用其中一个或另一个来逃避。
ResourcesCompat.getDrawable()
将在 API 21 岁或更大时调用 Resources#getDrawable(int, theme)
。它还支持 Android APIs 4+。无非是这样:
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
仅调用 res.getDrawable(id, theme)
。这意味着如果设备不支持矢量可绘制对象,它将不允许 允许绘制矢量可绘制对象。但是,它将允许您传递主题。
与此同时,AppCompatResources.getDrawable(Context context, int resId)
的代码更改最终会变成这样:
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;
}
所以这个实例如果可以的话它将尝试绘制资源,否则它会在 ContextCompat
版本中查找以获取资源。然后它甚至会在必要时对其进行着色。不过这个方法只支持API7+.
所以我想决定你是否应该使用其中之一,
您必须支持 API 4、5 或 6 吗?
- 是:别无选择,只能使用
ResourcesCompat
或ContextCompat
。 - 否:继续#2。
- 是:别无选择,只能使用
您绝对需要提供自定义主题吗?
- 是:别无选择,只能使用
ResourcesCompat
- 否:使用
AppCompatResources
- 是:别无选择,只能使用
上下文兼容性
ResourcesCompat
、ContextCompat
和几乎任何来自 support-v4 以 Compat
结尾的 class 都可以避免在任何地方编写 if (Build.VERSION.SDK_INT >= X)
检查。而已。例如,而不是
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);
}
你可以写
final Drawable d = ContextCompat.getDrawable(context, R.drawable.some_image);
注释中描述的限制适用,例如
// This line is effectively equivalent to the above.
ResourcesCompat.getDrawable(context.getResources(), R.drawable.some_image, context.getTheme());
实际上并没有在 Lollipop 之前应用主题属性(这在文档中有说明)。但是您不必编写 if 检查并且您的代码不会在旧设备上崩溃,因为您实际上并没有在那里使用新的 API。
AppCompatResources
另一方面,AppCompatResources
实际上会帮助您为旧平台带来新功能(支持向量、颜色状态列表中的主题参考)。
Which one should I prefer to another and why?
使用 AppCompatResources
获得与 appcompat-v7 库的其余部分一致的结果。你会得到:
getColorStateList
可以用主题属性引用解析颜色(比如android:alpha="?android:disabledAlpha"
),getDrawable
支持所有平台上的膨胀矢量,这些矢量可绘制对象也理解主题属性引用(例如android:tint="?colorControlNormal"
),- appcompat-v7 可绘制对象和颜色(如复选标记或单选按钮)将具有由提供的上下文主题定义的正确颜色,
- 如果以上不适用,则无论如何都会退回到
ContextCompat
。
这是我测试后的理解
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
首先看到的是VectorDrawableCompat
和ResourcesCompat
可以具体主题
I) 不使用
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
在 onCreated
中 class
1) 对于矢量图
API >= 21
ContextCompat
工作顺利ResourcesCompat
工作顺利AppCompatResources
工作顺利VectorDrawableCompat
工作顺利
API < 21
ContextCompat
崩溃ResourcesCompat
崩溃AppCompatResources
工作顺利VectorDrawableCompat
工作顺利
2) 对于普通图像
- 在所有级别
ContextCompat
工作顺利ResourcesCompat
工作顺利AppCompatResources
工作顺利VectorDrawableCompat
崩溃
II) 使用
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
在 onCreated
中 class
1) 对于矢量图
- 在所有级别
ContextCompat
工作顺利ResourcesCompat
工作顺利AppCompatResources
工作顺利VectorDrawableCompat
工作顺利
2) 对于普通图像
- 在所有级别
ContextCompat
工作顺利ResourcesCompat
工作顺利AppCompatResources
工作顺利VectorDrawableCompat
崩溃
API 19+ 解决方法
package com.example;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
/**
*
*/
public class AppDrawableCompat {
public static Drawable getDrawable(@NonNull Context context, @DrawableRes int resId) {
try {
return AppCompatResources.getDrawable(context, resId);
} catch (Resources.NotFoundException e1) {
try {
return ContextCompat.getDrawable(context, resId);
} catch (Resources.NotFoundException e2) {
return VectorDrawableCompat.create(context.getResources(), resId, context.getTheme());
}
}
}
@Nullable
public static Drawable findDrawable (@NonNull Context context, @DrawableRes int resId) {
try {
return getDrawable(context, resId);
} catch (Resources.NotFoundException e) {
return null;
}
}
public static void setViewBackgroundDrawable(@NonNull View view, @NonNull Context context, @DrawableRes int resId) {
Drawable drawable = findDrawable(context, resId);
if (drawable != null) {
view.setBackground(drawable);
}
}
}
使用示例 (MainActivity#onCreate)
ImageView icon = findViewById(R.id.icon);
AppDrawableCompat.setViewBackgroundDrawable(icon, this, R.drawable.bg_icon);