getDrawable()的效率:Drawable是否被框架缓存?

11

每次单击切换按钮时,我需要更改其图像。

这样做是否高效?

public void onClickToggleButton(View v) {
    if(_on) {
        _on=false;
        myImageView.setImageDrawable(getResources().getDrawable(R.drawable.btn_off));
    } else {
        _on=true;
        myImageView.setImageDrawable(getResources().getDrawable(R.drawable.btn_on));
    }
}

这是否意味着Drawable每次都会从PNG文件中解码?

如果是这样的话,在onCreate()中仅调用getDrawable()两次并保留自己对这2个Drawable的引用会更好。


2
请查看源代码http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/content/res/Resources.java#Resources.getDrawable%28int%29(如果您跟随方法调用,最终会进入缓存部分,最终进入BitmapState)(简短的答案是有一个WeakRef缓存,只要内存允许,就可以避免多次解码)。 - njzk2
顺便提一下,当 Android ToggleButton 已经完成状态添加时,你真的不应该自己添加状态;而且每次点击它时改变可绘制对象也是不必要的。相反,使用 StateListDrawable 来定义每个状态(开、关、按下、聚焦、禁用等)所使用的可绘制对象。 - njzk2
1
为什么要自己创建Drawable?直接调用setImageResource会更好。 - Stephane Mathis
@StephaneMathis 文档中警告不要在UI线程中调用setImageResource()。此外,我认为这种方法的效率与我提出的方法没有区别。 - Sébastien
2个回答

1
从Android API 28源代码开始,当您调用Resources#getDrawable时,将调用ResourceImpl#loadDrawable,该方法在其开头具有以下片段:
// If the drawable's XML lives in our current density qualifier,
// it's okay to use a scaled version from the cache. Otherwise, we
// need to actually load the drawable from XML.
final boolean useCache = density == 0 || value.density == mMetrics.densityDpi;

还有一个由Android Zygote进程操作的字段,称为ResourceImpl类中的mIsPreloading。如果useCache为true且ResourcesImpl未预加载,则使用可绘制对象的缓存版本。还有一些关于缓存ColorDrawables和themed Drawables的逻辑。

如果您像我一样需要Drawable的深层副本,并且这种缓存行为妨碍了您的工作,请查看此相关答案: Drawable的深层副本


0

这并不能回答你每次调用该方法是否高效的问题。 但是,正如@njzk2所指出的那样,你可以在切换按钮上使用状态选择器

我给你复制了一个可用的示例(我正在使用)。只需将drawable的名称更改为您自己的drawable即可。

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@drawable/toggle_on" android:state_checked="true" />
  <item android:drawable="@drawable/toggle_off" android:state_checked="false" />
</selector>

在您定义开关按钮的 XML 上,将背景设置为:

android:background="@drawable/toogle_selector"

"toogle_selector" 是我之前复制的文件名。

有了这个,你就可以忘记每次加载可绘制对象时的效率问题。

希望这能帮到你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接