0

I'm using two different libraries to achieve the same functionality, selectable by app flavor. So I created an interface class for either of the flavors like so:

public class Compat
{
  public static abstract class ActionBar extends android.support.v7.app.ActionBar {}

  public static abstract class FragmentManager extends android.support.v4.app.FragmentManager {}

  public static abstract class ActionBarActivity extends android.support.v7.app.ActionBarActivity
  {
    public FragmentManager getCompatFragmentManager()
    {
      return (FragmentManager) getSupportFragmentManager();  // <-- error
    }

    public ActionBar getSupportActionBar()
    {
      return (ActionBar) super.getSupportActionBar();  // <-- error
    }
  }

  public static class Fragment extends android.support.v4.app.Fragment {}
}

Basically this class just creates a bunch of "known" classes that are just aliases for their true underlying bases. Of course the true underlying bases can never be imported outside of this class. All further code only uses these "known" classes to derive from and perform other operations.

Later on in MainActivity.java:

class MainActivity extends Compat.ActionBarActivity {
  void doSomething()
  {
     Compat.ActionBar ab = getSupportActionBar();
     ...
  }
}

As you can see, if I want my Compat.ActionBarActivity to derive once from android.support.v7.app.ActionBarActivity and another time from android.support.v4.app.FragmentActivity, I can't afford to include both in MainActivity.java. I just include the Compat.java and use the classes declared there.

Everything is working nicely, except the indicated erroneous typecasts. Those throw an exception like

Caused by: java.lang.ClassCastException: android.support.v4.app.FragmentManagerImpl cannot be cast to com.velis.library.Compat$FragmentManager

Of course the getSupportFragmentManager doesn't return an object of my type, but I'm sure something can be done to make it so? Alternatively, is there any other way I can make an unknown class known?

Edit: my current solution (wrapper class):

import android.support.v4.app.FragmentActivity;

public class Compat
{
  public static class ActionBar
  {
    public android.app.ActionBar a;
    ActionBar(android.app.ActionBar ab) { a = ab; }
  }

  public static abstract class ActionBarActivity extends FragmentActivity
  {
    public android.app.FragmentManager getCompatFragmentManager()
    {
      return getFragmentManager();
    }

    public ActionBar getCompatActionBar()
    {
      return new ActionBar(getActionBar());
    }

    public void supportInvalidateOptionsMenu()
    {
      invalidateOptionsMenu();
    }
  }

  public static class Fragment extends android.app.Fragment {}
}

and MainActivity.java:

public class MainActivity extends Compat.ActionBarActivity
{
....
  public void restoreActionBar()
  {
    Compat.ActionBar actionBar = getCompatActionBar();
    actionBar.a.setNavigationMode(actionBar.a.NAVIGATION_MODE_STANDARD);
    actionBar.a.setDisplayShowTitleEnabled(true);
    actionBar.a.setTitle(mTitle);
  }
....
}

It's not pretty with that public member used, but so far it works. This question is about how to make this prettier.

velis
  • 8,747
  • 4
  • 44
  • 64
  • Thanks for the fine explanation about the downvote. Now I really know where I made my mistake, don't I? – velis Jun 02 '15 at 08:04
  • For more information about Java down casting you can read [this question](http://stackoverflow.com/questions/380813/downcasting-in-java) – Dalija Prasnikar Jun 02 '15 at 08:23
  • Please add more code and context to make it more clear what are you trying to to. You said you want to have two flavors, but I can only see one. How the other one looks and how do you want to use it in your app. Never mind errors, just show code you would like to have. Ultimately, the approach you are using is wrong, but it is hard to recommend better one because it is not clear what is the problem you are trying to solve. – Dalija Prasnikar Jun 02 '15 at 08:28
  • Hm, how else can I put this? I want this .java that contains the Compat class to be the only .java imported in my other code. As such, I need it to properly expose the required classes. So, I have `android.app.FragmentManager` and `android.support.v4.app.FragmentManager`, but further in the code I need both of them to just be a `FragmentManager` or whatever else for that matter, as long as it's one type that derives from either of the bases (and that I can use as such). – velis Jun 02 '15 at 08:31
  • Edited OP to show typical usage and (hopefully) issues involved with it. – velis Jun 02 '15 at 08:36
  • 1
    It is more clear now. Your question requires more elaborate answer, I cannot provide right now. If you don't get other answers in the mean time I will try to write it later on. – Dalija Prasnikar Jun 02 '15 at 09:26
  • I would appreciate it. Right now I'm using wrappers and they're ugly :( – velis Jun 02 '15 at 09:27
  • I am afraid I was about to suggest something along those lines... Can you add some example code you have and try to replace with your new solution. It would help to throw away solutions you already have but don't want to use. – Dalija Prasnikar Jun 02 '15 at 09:31
  • OP edited to reflect current solution – velis Jun 02 '15 at 09:59

0 Answers0