我遇到一种情况,需要根据onCreateDrawableState中的条件动态地设置自定义按钮的setBackground。
所以我的代码是这样的

public class MyButton extends Button  {
public boolean nightMode = false;
private Drawable dayBackground, nightBackgound;
public MyButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    setDuplicateParentStateEnabled(true);
    TypedArray a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.QITheme,
            0, 0);

    try {
        dayBackground = a.getDrawable(R.styleable.MyTheme_dayBackground);
        nightBackgound = a.getDrawable(R.styleable.MyTheme_nightBackground);
    } finally {
        a.recycle();
    }

}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
    int[] state = super.onCreateDrawableState(extraSpace+1);
    if (CurrentThemeManager.isNightMode()) {
        if(nightBackgound != null)
            setBackground(nightBackgound);
    } else {
        if(dayBackground != null)
            setBackground(dayBackground);
    }
    return state;
}


}

但是由于setBackground间接调用onCreateDrawableState,由于无限递归调用,我得到了StackOverflowError

java.lang.StackOverflowError
        at android.view.ViewGroup.onCreateDrawableState(ViewGroup.java:5370)
        at android.view.View.onCreateDrawableState(View.java:14635)
        at android.view.ViewGroup.onCreateDrawableState(ViewGroup.java:5370)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:69)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76)
        at android.view.View.getDrawableState(View.java:14611)
        at android.view.View.setBackgroundDrawable(View.java:14837)
        at android.view.View.setBackground(View.java:14777)
        at my.mytheme.widget.MyButton.onCreateDrawableState(MyButton.java:76


有人可以帮我解决此StackOverflowError吗?

最佳答案

您不应从setBackground呼叫onCreateDrawableState。这是懒惰的方式。但应改为更改可绘制状态。

像这样煮:


在选择器中定义您的可绘制对象(例如,使用state_checked)




<item android:state_checked="false"
    android:drawable="@drawable/night_image" />
<item android:state_checked="true"
    android:drawable="@drawable/day_image" />



在您的自定义视图中添加状态处理

class YourFancyView extends SomeView implement Checkable {

    private static final int[] CHECKED_STATE_SET = {
            android.R.attr.state_checked
    };

    @Override
        protected int[] onCreateDrawableState(int extraSpace) {
            final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);

            if (isChecked()) {
                mergeDrawableStates(drawableState, CHECKED_STATE_SET);
            }
            return drawableState;
        }

@Override
public void setChecked(boolean checked) {
    if(mChecked != checked) {
        mChecked = checked;
        refreshDrawableState();

    }
}

下一步-以任何合理的方式设置checked状态的代码。

YourFancyView v =新的YourFancyView();
if(itIsTime)v.setChecked(true);


这应该可以解决问题。

09-25 16:06