I created some custom component based on ConstraintLayout in Android Studio. First I created base abstract class called MyButton where I do some basic stuff (e.g. get references to my components). Next I created derived class called MySpecialButton that extends MyButton, but I have strange behavior when I attach onClickListener to my Button, that is a part of my custom component, and call method that modify element (reference) that exists only in MySpecialButton from onClickListener.
In a present code, when i try call setImage()
from onClickListener, this end up with log: E/NULL: ImageView reference is null!
which means that from point of view onClickListener, reference vImageViev
is null, however it is initialized in inflateView
call. But when I call setImage()
not from onClickListener but directly from init()
method after inflateView(R.layout.my_special_button)
everything is OK.
Also when I move protected ImageView vImageView = null;
declaration from MySpecialButton to MyButton everything is OK.
This is my 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);
}
}
and this is my 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);
}
}
What's going on? What I should do to be able call setImage()
from onClickListener without null reference?
I think you are doing wrong super calls in your constructors:
This
public MySpecialButton(Context context, AttributeSet attr)
{
this(context);
}
Should be:
public MySpecialButton(Context context, AttributeSet attr)
{
super(context, attr);
}
Same for the other class. And move your custom init in a different function you call from each constructor.