Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Workaround for support.v4.app.Fragment -> Fragment classcastexception?

I'm trying to add a support.v4.app.Fragment to a PreferenceActivity header, like so:

<header
    android:fragment="com.example.SupportFragmentSubClass"
    android:title="Selecting this should show the accompanying fragment" >
</header>

This throws a ClassCastException, presumably because the PreferenceActivity is expecting a sub-class of android.app.Fragment, rather than support.v4.app.Fragment.

My use case is this:
I have non-standard Fragment that I want to use as a preference on both <3.0 and >3.0 devices. For >=3.0, I need an android.app.Fragment subclass so it can be embedded in the 'detail pane' of the preferences activity on tablet devices. For <3.0, I need a v4.support.app.Fragment subclass so I can throw in it an ActivityFragment.

Is there a workaround that would allow me to use a compatibility Fragment in this situation?

like image 292
koi-feeding Avatar asked Jan 29 '12 14:01

koi-feeding


2 Answers

PreferenceFragment is not in the Android Support package, and you cannot use an Android Support package Fragment class in a PreferenceActivity this way. Moreover, your headers would not work on Android 2.x anyway, since the PreferenceActivity in Android 2.x does not know about fragments.

In principle, you could fork the PreferenceActivity from the source code to create one that does use the Android Support version of Fragment.

Or, organize your preferences to use fragments on Android 3.0+ and avoid them on Android 2.x. Here is a sample project where I demonstrate a way to do this.

like image 73
CommonsWare Avatar answered Oct 10 '22 17:10

CommonsWare


As @CommonsWare points out, it's not possible to what I wanted without rewriting PreferenceActivity, and that looks like a load of work.

The not-so-elegant solution I settled on was to create two PreferenceActivities (as shown here) and also create two Fragment subclasses, one for each flavour of Fragment.

So, PrefsActivityHC adds this header:

<header
    <!-- An android.app.Fragment subclass -->
    android:fragment="com.example.project.MyFragmentHC"
</header>

...while PrefsActivity adds this preference:

<Preference>
    <intent
        <!-- A v4.support.app.Fragment subclass, wrapped in an ActivityFragment -->
        android:targetClass="com.example.project.MyFragmentActivity"
        android:targetPackage="com.example.project" >
    </intent>
</Preference>

To minimise the amount of code duplication required to have two near-identical fragments, I created a MyFragmentDelegate class that supports common fragment methods, and held an instance of that in MyFragment and MyFragmentHC. Calls to the methods in these fragments are then just forwarded to the delegate:

class MyFragment {

    MyFragmentDelegate mDelegate;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return mDelegate.onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    }
}

class MyFragmentHC {

    MyFragmentDelegate mDelegate;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return mDelegate.onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    }
}
like image 40
koi-feeding Avatar answered Oct 10 '22 17:10

koi-feeding