How to modify attributes before passing them to a superclass constructor?

stevendesu :

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?

GhostCat salutes Monica C. :

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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=77382&siteId=1