jwir3
jwir3

Reputation: 6209

Unable to initialize nested Fragment due to it being abstract on rotation

I have the following object hierarchy:

          BaseMessageListFragment (abstract)
                 ^
                 |
                 /\
                /  \
               /    \
              /      \
             /        \
            /          \
           /            \
          /              \
         |                |
SwapMessageListFragment  RequestMessageListFragment

Now, each of these fragments (SwapMessageListFragment and RequestMessageListFragment) is actually nested within another Fragment. Taking, for example, the case of SwapMessageListFragment, it's nested within a class called SwapDetailFragment.

This works fine, but when I change orientation when SwapDetailFragment is displayed, I get the following crash:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.app/com.example.app.ui.shift.ShiftDetailActivity}: android.view.InflateException: Binary XML file line #57: Error inflating class fragment
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3947)
            at android.app.ActivityThread.access$900(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: android.view.InflateException: Binary XML file line #57: Error inflating class fragment
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:763)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at com.example.app.ui.shift.fragment.SwapDetailFragment.onCreateView(SwapDetailFragment.java:559)
            at android.support.v4.app.Fragment.performCreateView(Fragment.java:1789)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:955)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1138)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1120)
            at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1929)
            at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
            at com.example.app.ui.BaseActivity.onStart(BaseActivity.java:161)
            at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1236)
            at android.app.Activity.performStart(Activity.java:6006)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3947)
            at android.app.ActivityThread.access$900(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.example.app.ui.message.fragment.BaseMessageListFragment: make sure class name exists, is public, and has an empty constructor that is public
            at android.support.v4.app.Fragment.instantiate(Fragment.java:432)
            at android.support.v4.app.Fragment.instantiate(Fragment.java:396)
            at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2162)
            at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
            at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:177)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:725)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at com.example.app.ui.shift.fragment.SwapDetailFragment.onCreateView(SwapDetailFragment.java:559)
            at android.support.v4.app.Fragment.performCreateView(Fragment.java:1789)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:955)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1138)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1120)
            at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1929)
            at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
            at com.example.app.ui.BaseActivity.onStart(BaseActivity.java:161)
            at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1236)
            at android.app.Activity.performStart(Activity.java:6006)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3947)
            at android.app.ActivityThread.access$900(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.InstantiationException: class com.example.app.ui.message.fragment.BaseMessageListFragment cannot be instantiated
            at java.lang.Class.newInstance(Class.java:1587)
            at android.support.v4.app.Fragment.instantiate(Fragment.java:421)
            at android.support.v4.app.Fragment.instantiate(Fragment.java:396)
            at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2162)
            at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
            at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:177)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:725)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at com.example.app.ui.shift.fragment.SwapDetailFragment.onCreateView(SwapDetailFragment.java:559)
            at android.support.v4.app.Fragment.performCreateView(Fragment.java:1789)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:955)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1138)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1120)
            at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1929)
            at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
            at com.example.app.ui.BaseActivity.onStart(BaseActivity.java:161)
            at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1236)
            at android.app.Activity.performStart(Activity.java:6006)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
            at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3947)
            at android.app.ActivityThread.access$900(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1309)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

Since BaseMessageListFragment is abstract, I'm not sure why it's trying to initialize this Fragment. I originally had a reference to a member variable in SwapDetailFragment called mMessageFrag which was defined as follows:

private BaseMessageListFragment mMessageFrag;

I've tried making this a SwapMessageListFragment instead, but with no luck. Additionally, I've tried adding default constructors to BaseMessageListFragment (which seems a waste, since it can't be instantiated, anyway), SwapMessageListFragment, and RequestMessageListFragment, but, again, with no joy. Finally, I even attempted to create a newInstance() implementation on BaseMessageListFragment like the following:

  public static BaseMessageListFragment newInstance(Class<? extends GsonBase> aBaseObjectType,
                                                    long aBaseObjectId) {
    BaseMessageListFragment retVal;

    Bundle args = new Bundle();
    // Add arguments here
    retVal.setArguments(args);

    return retVal;
  }

(as advised in Do fragments really need an empty constructor? ), but still with no luck.

I'm not sure what I'm doing incorrectly that causes Android to want to instantiate the base class, rather than a derived class.

EDIT:

As requested, here is a view of the fragment_swap_detail.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:background="#FFFFFF">

    <RelativeLayout android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <FrameLayout android:id="@+id/request_header" style="@style/Material.View.Detail.Header" android:paddingTop="0dp" android:paddingBottom="0dp">
            <include android:id="@+id/swap_block" layout="@layout/list_item_request_block" android:layout_width="fill_parent" android:layout_height="wrap_content" />
        </FrameLayout>

        <LinearLayout android:layout_width="fill_parent" android:layout_height="59dp" 
            android:orientation="horizontal"
            android:background="@drawable/button_bar_background"
            android:layout_alignParentBottom="true"
            android:padding="10dp">
            <Button style="@style/Material.Widget.Button.Green" android:id="@+id/button_approve"
                android:layout_width="0dp" 
                android:layout_height="38dp" 
                android:layout_weight="1" 
                android:text="Approve" />
            <Button style="@style/Material.Widget.Button.Red" android:id="@+id/button_decline"
                android:layout_width="0dp" 
                android:layout_height="38dp" 
                android:layout_weight="1" 
                android:text="Decline" />
            <Button style="@style/Material.Widget.Button" android:id="@+id/button_cancel"
                android:layout_width="0dp" 
                android:layout_height="38dp" 
                android:layout_weight="1" 
                android:text="Cancel" />
        </LinearLayout>
    </RelativeLayout>
    <View android:layout_width="6dp" android:layout_height="match_parent" android:background="#CCCCCC" />
    <ScrollView android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"
        android:paddingLeft="@dimen/padding_listview"
        android:paddingRight="@dimen/padding_listview"
        android:scrollbarStyle="outsideOverlay"
        >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView style="@style/Material.View.Detail.Row.Header" android:id="@+id/tableheader_messages" android:text="Messages" />

            <EditText android:id="@+id/swap_message"
                android:visibility="gone"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="text|textAutoCorrect|textMultiLine" />

            <fragment
                android:id="@+id/fragment_messages"
                android:name="com.example.app.ui.message.fragment.BaseMessageListFragment"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <TextView style="@style/Material.View.Detail.Row.Header" android:id="@+id/tableheader_takers" android:text="Potential Takers" />
            <fragment
                android:id="@+id/fragment_check"
                android:name="com.example.app.ui.base.list.BaseCheckListFragment"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"/>
        </LinearLayout>
    </ScrollView>
</LinearLayout>

Upvotes: 0

Views: 397

Answers (1)

Gennadii Saprykin
Gennadii Saprykin

Reputation: 4573

I don't think you can inflate an abstract Fragment via XML. Replace your fragment with a FrameLayout and use FragmentManager to load a fragment to that layout in runtime.

You should do that only once. After screen rotation your savedInstanceState won't be null, so your fragment will be there - FragmentManager handles that for you.

Upvotes: 1

Related Questions