使用ViewPager的FragmentActivity:屏幕旋转时崩溃

6

我在FragmentActivity中使用了ViewPager。屏幕方向改变时,发生了崩溃。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list);
    context = this;
    loadInitialData();
    setActionBar();
    initializeUiComponents();
}

private void initializeUiComponents() {
    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    }

我的数据是从数据库动态获取的,我必须在onResume()中调用获取数据的Sysnctask。以下是Asynctask的onPostExecute()。

protected void onPostExecute(Void result) {
        
            mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
            mViewPager.setAdapter(mSectionsPagerAdapter);
        }
        mSectionsPagerAdapter.notifyDataSetChanged();
        }
}

添加 FragmentAdapter 代码:

public class SectionsPagerAdapter extends FragmentPagerAdapter {
    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }
    
    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page.
        // Return a DummySectionFragment (defined as a static inner class
        // below) with the page number as its lone argument.
        Fragment fragment = new PayeeListSectionFragment();
        Bundle args = new Bundle();
        args.putInt(PayeeListSectionFragment.ARG_SECTION_NUMBER, position + 1);
        fragment.setArguments(args);
        return fragment;
    }
    
    @Override
    public int getCount() {
        return 2;
    }
    
    @Override
    public CharSequence getPageTitle(int position) {
        
        return string;
    }
}

添加片段代码:

public class PayeeListSectionFragment extends Fragment {
    /**
     * The fragment argument representing the section number for this fragment.
     */
    public static final String ARG_SECTION_NUMBER = "section_number";
    
    public PayeeListSectionFragment() {
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = null;
        \\ rootView inflated
        return rootView;
    }
}

所使用的XML为:

 <android.support.v4.view.ViewPager
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".PayeeListActivity" >

    <!--
This title strip will display the currently visible page title, as well as the page
titles for adjacent pages.

    -->

    <android.support.v4.view.PagerTitleStrip
        android:id="@+id/pager_title_strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:background="#33b5e5"
        android:paddingBottom="4dp"
        android:paddingTop="4dp"
        android:textColor="#fff" />
</android.support.v4.view.ViewPager>

我在屏幕方向变化时遇到了以下崩溃问题:
06-07 11:01:57.834: E/AndroidRuntime(766): FATAL EXCEPTION: main  
06-07 11:01:57.834: E/AndroidRuntime(766): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.walletv2.activity/com.walletv2.activity.PayeeListActivity}: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.walletv2.activity.PayeeListActivity$PayeeListSectionFragment: make sure class name exists, is public, and has an empty constructor that is public  
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3692)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.ActivityThread.access$700(ActivityThread.java:141)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1240)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.os.Handler.dispatchMessage(Handler.java:99)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.os.Looper.loop(Looper.java:137)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.ActivityThread.main(ActivityThread.java:5041)
06-07 11:01:57.834: E/AndroidRuntime(766):  at java.lang.reflect.Method.invokeNative(Native Method)
06-07 11:01:57.834: E/AndroidRuntime(766):  at java.lang.reflect.Method.invoke(Method.java:511)
06-07 11:01:57.834: E/AndroidRuntime(766):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
06-07 11:01:57.834: E/AndroidRuntime(766):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
06-07 11:01:57.834: E/AndroidRuntime(766):  at dalvik.system.NativeStart.main(Native Method)
06-07 11:01:57.834: E/AndroidRuntime(766): Caused by: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.walletv2.activity.PayeeListActivity$PayeeListSectionFragment: make sure class name exists, is public, and has an empty constructor that is public
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.support.v4.app.Fragment.instantiate(Fragment.java:405)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.support.v4.app.FragmentState.instantiate(Fragment.java:97)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.support.v4.app.FragmentManagerImpl.restoreAllState(FragmentManager.java:1767)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:208)
06-07 11:01:57.834: E/AndroidRuntime(766):  at com.walletv2.activity.PayeeListActivity.onCreate(PayeeListActivity.java:78)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.Activity.performCreate(Activity.java:5104)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
06-07 11:01:57.834: E/AndroidRuntime(766):  ... 12 more
06-07 11:01:57.834: E/AndroidRuntime(766): Caused by: java.lang.InstantiationException: can't instantiate class com.walletv2.activity.PayeeListActivity$PayeeListSectionFragment; no empty constructor
06-07 11:01:57.834: E/AndroidRuntime(766):  at java.lang.Class.newInstanceImpl(Native Method)
06-07 11:01:57.834: E/AndroidRuntime(766):  at java.lang.Class.newInstance(Class.java:1319)
06-07 11:01:57.834: E/AndroidRuntime(766):  at android.support.v4.app.Fragment.instantiate(Fragment.java:394)
06-07 11:01:57.834: E/AndroidRuntime(766):  ... 19 more
1个回答

7
以下几行中提供了一些提示:
由于:android.support.v4.app.Fragment$InstantiationException: 无法实例化片段com.walletv2.activity.PayeeListActivity $ PayeeListSectionFragment:确保类名存在、是公共的,并且具有公共的空构造函数 和:
06-07 11:01:57.834: E/AndroidRuntime(766): 由于:java.lang.InstantiationException:无法实例化类com.walletv2.activity.PayeeListActivity $ PayeeListSectionFragment;没有空构造函数 这表明您已经向内部类PayeeListSectionFragment添加了参数化构造函数。不幸的是,这样做行不通,因为Android依赖于使用反射调用非参数化构造函数来恢复片段的状态以进行配置更改(以及其他事情)。

如果你想向片段(fragment)提供一个或多个参数,你需要将它们放入一个Bundle中,并将其设置为参数(argument),使用setArguments(Bundle)。查看文档中的DetailsFragmentCountingFragment示例了解如何操作。


这个问题也可能在另一种情况下出现,对于不太熟悉Java的人来说可能不太明显。如果您的片段是某个Activity的嵌套类,请确保声明内部类为static。例如,在上面的问题上下文中,它应该是一个public static class PayeeListSectionFragment(强调static修饰符)。这样,内部类就不会保留对外部类的引用,可以拥有自己的生命周期,而不依赖于外部类。如果没有static修饰符,嵌套类无法在不实例化外部类的情况下实例化,这意味着Android在尝试重新实例化您的片段类时会遇到问题。
另一种解决方法是将内部类移动到自己的.java文件中。这样,任何外部类依赖项都会被自动删除。

@Vineet:嗯,要么是你添加了一个(非参数化的)构造函数,它是私有的、受保护的或包保护的,而不是public。如果你能在问题中添加相关的代码片段,那会很有帮助。我们越猜测,找到确切的问题就越容易。 - MH.
我已经添加了FragmentpagerAdapter和Fragment代码。请帮忙。 - Vineet
2
@Vineet:由于你的片段是一个嵌套类,你需要将它变成public static class PayeeListSectionFragment(注意static修饰符),这样它就不会保留对外部类的引用。否则,你的嵌套类无法在不实例化外部类的情况下被实例化,这可能就是你目前看到的错误原因。如果你不是很理解,只需将该片段移动到自己的文件中即可。如果没有依赖于外部类,那么这也应该解决问题。 - MH.
非常感谢!它解决了问题。您能告诉我动态实现片段的最佳方法吗? - Vineet
@Vineet:很高兴听到那对你有用。我不确定你最后一句话的意思,但是你可以在SO上提出另一个问题,详细说明你遇到的困难。 - MH.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接