3

I created an abstract class to prevent redundant code in each of my activities.

public abstract class MyGeneralizedActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }

        @Override
        public void attachBaseContext(Context newBase) {
            super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
        }
      //...
 }

I was perfectly fine by doing this:

public class MyActivity extends MyGeneralizedActivity{...}

But now I got to the point where I have to extend MyActivity from FragmentActivity. That means I can't extend from MyGeneralizedActivity anymore.

Now I am wondering if it's possible to set up a general abstract structure to extend all of my activities.

EDIT
Just by extending MyGeneralizedActivity from FragmentActivity won't solve my problem. e.g. TabActivity will lead to the same issue.

UPDATE
For those who may be interested in solving the same problem in Android I've found a simple workaround. There exist the Application class, which provides, among other things, the interface ActivityLifecycleCallbacks. It does exactly what I need allowing us to intercept and add some value into important events for all activities.

All you have to do is to extend the Android Application Class and create a private class within which implements ActivityLifecycleCallbacks.
Don't forget to add/rename your Application in your AndroidManifests file:

<application
     android:name=".application.MyApplication" 
     //...
/>
spyfx
  • 1,311
  • 4
  • 14
  • 24
  • You can create a interface with default method if using Java 8. Then you can implement multiple interfaces this way and get desired result. – Aaditya Gavandalkar Dec 29 '15 at 19:21
  • 3
    Given [`FragmentActivity` is itself a subclass of `Activity`](http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html), is there any reason you can't just make `MyGeneralizedActivity extends FragmentActivity` ? – PPartisan Dec 29 '15 at 19:21
  • 1
    Why aren't you extending from AppCompatActivity? Also, just curious, what requirement do you have for FragmentActivity? – AdamMc331 Dec 29 '15 at 19:21
  • @PPartisan edited my main post. – spyfx Dec 29 '15 at 19:29
  • This is why composition is favored over inheritance. http://stackoverflow.com/q/11343840/3474528 – Charles Durham Dec 29 '15 at 19:41

4 Answers4

1

As both FragmentActivity and MyGeneralizedActivity are classes and not interfaces there is no way to create a type that is a subtype of both.

Java limits you to single inheritance, so if you're dependent on sharing implementation that's included in two classes, your best bet here is relying on composition instead.

For example:

public class MyActivity extends Activity { 
  FragmentActivity fragmentActivity;
  MyGeneralizedActivity myGeneralizedActivity;

  public MyActivity(FragmentActivity fragmentActivity, MyGeneralizedActivity myGeneralizedActivity) {
    this.fragmentActivity = fragmentActivity;
    this.myGeneralizedActivity = myGeneralizedActivity;
  }


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    this.fragmentActivity.onCreate(savedInstanceState);
    this.myGeneralizedActivity.onCreate(savedInstanceState);
    //...
  }

  @Overridepublic void attachBaseContext(Context newBase) {
    this.fragmentActivity.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
    this.myGeneralizedActivity.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
    //...
  }

}
vpiTriumph
  • 3,116
  • 2
  • 27
  • 39
  • 1
    I don't think you can overload an `Activity` class's constructor in this way. – PPartisan Dec 29 '15 at 19:30
  • Upon closer inspection `Activity`, does have a default constructor, so you should be able to instantiate a subtype of `Activity` exactly as I've proposed unless I'm missing something. – vpiTriumph Dec 29 '15 at 19:35
  • I'm thinking of the answer to [this](http://stackoverflow.com/a/28636652/1219389) question (and a few [others](http://stackoverflow.com/a/8555673/1219389)), which specify all `Activity` classes use their default constructor. – PPartisan Dec 29 '15 at 19:45
1

This seems like a problem for the Decorator Pattern.

Intent

  • Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
  • Client-specified embellishment of a core object by recursively wrapping it.
  • Wrapping a gift, putting it in a box, and wrapping the box.

Problem

You want to add behavior or state to individual objects at run-time. Inheritance is not feasible because it is static and applies to an entire class.

Structure

The canonical form: Decorator Pattern Diagram

Thinking specifically about your case, since Android API does not define an interface for Activity, we could skip some bureaucracy and just do it in the (not so) quick and dirty way:

abstract public class ActivityDecorator extends Activity {
    protected Activity original;

    public MyAcitvityDecorator(Activity original) {
        this.original = original;
    }

    protected void onCreate(Bundle savedInstanceState) {
        this.original.onCreate(savedInstanceState);
    }

    /* ... Because there is no better way of doing it in Java, you should do
     * this for every method in the Activity class: delegate the execution of 
     * the method to the original activity object.
     * Yes, there is A LOT of methods!
}

Then you must create a concrete decorator and override the due methods:

class MyActivityDecorator extends ActivityDecorator {
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            this.original.onCreate(savedInstanceState);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }

        @Override
        public void attachBaseContext(Context newBase) {
            this.original.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
        }
}

Then you can use it like this:

Activity myActivity = new MyActivityDecorator(new Activity());

Because MyAcitvityDecorator is an instance of Activity, you can pass it around seemlessly.

You could even chain decorators and change the original Activity object like this:

Activity myActivity = new MyActivityDecorator(
    new AnotherActivityDecorator(
        new TabActivity()
    )
);
Henrique Barcelos
  • 7,670
  • 1
  • 41
  • 66
0

See in FragmentActivity source code. FragmentActivity extends Activity class. I think you should try and see.

Best of luck.

Mohammad Tauqir
  • 1,817
  • 1
  • 18
  • 53
0

You can create a interface with default method if using Java 8. Then you can implement multiple interfaces this way and get desired result.

Refer for details: Interface with default methods vs Abstract class in Java 8

Community
  • 1
  • 1
  • Can you elaborate a bit more on this proposal? Ideally provide an example. While it is true that it is possible to create a default implementation for interfaces in Java 8 there are limitations (e.g. you don't have access to instance state) so this is not necessarily a solution. – vpiTriumph Dec 29 '15 at 19:45