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.