ImageView 引用和派生的奇怪行为 class

Strange behavior with ImageView reference and derived class

我在 Android Studio 中基于 ConstraintLayout 创建了一些自定义组件。首先,我创建了名为 MyButton 的基础抽象 class,我在其中做一些基本的事情(例如获取对我的组件的引用)。接下来,我创建了派生的 class,称为 MySpecialButton,它扩展了 MyButton,但是当我将 onClickListener 附加到我的 Button 时,我有奇怪的行为,这是我的自定义组件的一部分,并调用修改仅存在于中的元素(参考)的方法来自 onClickListener 的 MySpecialButton。

在目前的代码中,当我尝试从 onClickListener 调用 setImage() 时,结果为日志:E/NULL: ImageView reference is null!,这意味着从 onClickListener 的角度来看,引用 vImageViev 为空,但是它是在 inflateView 调用中初始化的。但是当我在 inflateView(R.layout.my_special_button) 之后不是从 onClickListener 而是直接从 init() 方法调用 setImage() 时,一切正常。 此外,当我将 protected ImageView vImageView = null; 声明从 MySpecialButton 移动到 MyButton 时,一切正常。

这是我的 MyButton class:

public abstract class MyButton extends ConstraintLayout
{
    protected Context context = null;

    protected View rootView = null;
    protected Button vButton = null;
    protected Switch vSwitch = null;

    public MyButton(Context context)
    {
        super(context);
        this.context = context;
        init();
    }

    public MyButton(Context context, AttributeSet attrs)
    {
        this(context);
    }

    protected abstract void init();

    protected void inflateView(int res)
    {
        rootView = inflate(context, res, this);

        vButton = (Button)rootView.findViewById(R.id.vButton);
        vSwitch = (Switch)rootView.findViewById(R.id.vSwitch);
    }
}

这是我的 MySpecialButton class:

public class MySpecialButton extends MyButton
{
    protected ImageView vImageView = null;

    public MySpecialButton(Context context)
    {
        super(context);
    }

    public MySpecialButton(Context context, AttributeSet attr)
    {
        this(context);
    }


    @Override
    protected void inflateView(int res)
    {
        super.inflateView(res);

        vImageView = (ImageView)rootView.findViewById(R.id.vImageView);
    }

    protected void init()
    {
        inflateView(R.layout.my_special_button);

        vButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                setImage();
            }
        });
    }

    protected void setImage()
    {
        if(vImageView == null)
            Log.e("NULL", "ImageView reference is null!");
        else
            vImageView.setImageResource(R.drawable.ic_window);
    }
}

这是怎么回事?我应该怎么做才能在没有空引用的情况下从 onClickListener 调用 setImage()

那是因为 setOnClickListenter 是为基础 class(即 ConstraintLayout)调用的,因为您没有在子 class 中覆盖它无法访问 ImageView。

试试这个:

public abstract class MyButton extends ConstraintLayout
{
    protected Context context = null;

    protected View rootView = null;
    protected Button vButton = null;
    protected Switch vSwitch = null;

    //...

    @Override
    public void setOnClickListener(@Nullable OnClickListener l) {
        vButton.setOnClickLisnter(l);
    }
}

我认为您在构造函数中进行了错误的超级调用:

这个

public MySpecialButton(Context context, AttributeSet attr)
{
    this(context);
}

应该是:

public MySpecialButton(Context context, AttributeSet attr)
{
    super(context, attr);
}

另一个相同 class。并将您的自定义 init 移动到您从每个构造函数调用的不同函数中。