0

I'm not sure SO is the right place to ask this question so let me know if I should maybe post it on ProgrammersSE.

I've got an Android library project which comes with some functionality and some basic XML files. In the nearest future I'll be developing multiple apps which will heavily depend on that library - it's possible that some of them will only differ in that they'll be using different XML layout files and image resources. As far as I know Android will automatically pick the ones from the regular projects instead of the library one if the names of the appropriate files are the same so this shouldn't be a problem.

The problem is I expect that some of the projects will have to have a slightly extended functionality - meaning I'd have to, e.g., extend the classes which are in the library project.

I just tried that out but obviously that didn't work as I wasn't overriding the entire code of a class - just adding to it, meaning I seemingly can't have the the library Activities call the classes from my regular project.

Is there any way around that without using reflection?

Is there maybe a better way of handling such a situation?

Edit for clarification:

Thanks to @jucas and @Alex Cohn for the answers and the links. I'm not sure if the solutions you wrote are applicable to my situation - I'd probably have to see examples of those coded to decide if I can do anything similar in my project.

Here's an example of what makes this problematic for me: say in my library project I've got a class called MyActivity which extends Activity and implements OnScrollChangedListener because there's a ScrollView in it whose background has to scale. There could be something like this in it:

@Override
public void onScrollChanged() {

    int currentScrollOffsetY = this.scrollView.getScrollY();

    // No case for further back than the bottom of the screen (lower than 0)
    // and if it's higher than where it should stop, keep it at that point
    if (currentScrollOffsetY > this.screenHeightPx * MULTIPLIER_Y_ANIMATION_STOP) {

        currentScrollOffsetY = (int) (this.screenHeightPx * MULTIPLIER_Y_ANIMATION_STOP);
    }

    // Set the pivot points of the background images
    this.imageBackground.setPivotX(this.imageBackground.getWidth() / 2.0f);
    this.imageBackground.setPivotY(0);

    // Scale the background
    float newBackgroundScale = 1 - (float) currentScrollOffsetY / (float) this.screenHeightPx;

    if (newBackgroundScale < 0.75f) {

        newBackgroundScale = 0.75f;
    }

    this.imageBackground.setScaleX(newBackgroundScale);
    this.imageBackground.setScaleY(newBackgroundScale);
}

As you can see, the new scale for the background image is never smaller than 0.75 of the original size. Now if one of the projects using the library project needed that to be 0.8 instead, I could just move the value from the code to the XML values resources and it should be dynamically read from there - that's perfectly fine.

But what if I not only wanted to do that but also scale another ImageView?

    this.imageBackground.setScaleX(newBackgroundScale);
    this.imageBackground.setScaleY(newBackgroundScale);
    this.differentImageBackground.setScaleX(newBackgroundScale);
    this.differentImageBackground.setScaleY(newBackgroundScale);

How could this be achieved? I'm sorry if I don't understand this straight away - I've never done anything like this yet and some concepts are a bit difficult for me to get my head around them.

JakeP
  • 1,736
  • 4
  • 23
  • 31

2 Answers2

1

This a very common problem, and one that has several answers that might or might not be the best for your particular case, here are 2 from the top of my mind:

  1. Develop a plugin architecture for your app, to load content and functionality from plugins Plugins architecture for an Android app?, note that this might be overkill if you just need to change a few classes here and there.

  2. Modify your library project's architecture: This is one that I tend to use the most, just because it is simply and doesn't require a very complex refactoring. The steps needed for this are usually like this:

    a. Figure out which parts of your activity or fragment might need to be extended by your main app project

    b. Create interfaces and classes that implement those interfaces for the extendable functionality

    c. This is the tricky part, isolate the creation and use of those classes in specific methods inside your activities or fragments

    d. Finally on your main app project, create new classes that implement the same interfaces and override your fragments or activites to create these classes instead

I hope this helps you a bit, and if it doesn't you might want to sketch out some code in order to see exactly what problems you are having

Community
  • 1
  • 1
Julian Suarez
  • 4,499
  • 4
  • 24
  • 40
  • Thank you for your comment; could you take a look at the edit I made to my original question? – JakeP Oct 24 '14 at 08:50
1

This looks like a good fit for "inversion of control" design pattern. If a ExtendsActivity class is not changed between projects, but sometimes it uses an actor of class MyActor and sometimes ExtendsMyActor, then you should prepare a way for ExtendsActivity to accept the reference to such actor. You can inject this reference on construction, or later during the lifecycle of activity.

It is often recommended to use interface, i.e. define IActor and have both MyActor and any alternative implements this interface. But in some cases, extends fits perfectly, too.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Thank you for your comment; could you take a look at the edit I made to my original question? – JakeP Oct 24 '14 at 08:49