The general question:
Given a class like so:
public class Super {
private String value;
public Super(String initialValue)
{
this.value = initialValue;
}
public String getValue()
{
return value;
}
}
And a subclass like so:
public class Sub extends Super {
public Sub(String initialValue)
{
super(initialValue);
}
}
Is there a way to modify initialValue
before calling the super()
method?
Here's my specific use case:
I'm writing a small wrapper ExoPlayer, like so:
public class BFPlayer extends PlayerView {
private SimpleExoPlayer player;
public BFPlayer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
TypedArray attributes = context.obtainStyledAttributes(attrs,
R.styleable.BFPlayer);
player = ExoPlayerFactory.newSimpleInstance(context);
this.setPlayer(player);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
Util.getUserAgent(context, "TODO: USER AGENT STRING"));
MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(attributes.getString(R.styleable.BFPlayer_videoSrc)));
player.prepare(videoSource);
player.setPlayWhenReady(true);
}
}
ExoPlayer's PlayerView
View expects attributes (in the layout.xml
file) to use snake case. For example:
use_artwork
default_artwork
hide_on_touch
- etc
However the vast majority of default attributes for native Views use camel case:
addStatesWithChildren
alwaysDrawnWithCache
animateLayoutChanges
animateCache
clipChildren
clipToPadding
- etc
Therefore for consistency I would like to replace the ExoPlayer attributes with identical camel case attributes:
useArtwork
defaultArtwork
hideOnTouch
- etc
However because super()
must be called before any other code in the constructor, I don't have an opportunity to modify the AttributeSet before the superclass initializes:
public BFPlayer(Context context, AttributeSet attrs, int defStyle) {
AttributeSet modifiedAttrs = camelToSnake(attrs);
super(context, modifiedAttrs, defStyle);
init(context, attrs, defStyle);
}
Is there a trick to this? Or is it simply impossible?
Ideally, you would do something like:
class Sub extends Super {
private static String massageArgument(String incoming) {
return incoming.replaceAll("foo", "bar");
}
public Sub(String incoming) {
super(massageArgument(incoming));
}
And note: that method needs to be static! You can't use a non-static method within that call to the super constructor in Sub. As any non-static method might expect that it operates on fully initialized objects. Which you don't have, when you invoke the method before the "this" and the "super" constructor were invoked and could do their initialisation work!
The other option would be to make the Sub constructor private, and have a static factory method that manipulates the incoming string, and then calls new Sub()
right away with the massaged input.