Fragment和FragmentStatePagerAdapter中的ViewPager片段导致exception(具有完整的示例)

我有一个ViewPager简单的片段。

我正在使用最新的支持库v4 rev18!

如果我第一次显示子片段,一切正常,如果我回去再次显示,应用程序崩溃,但有以下例外:

我有一个完整的例子显示,当下面的exception发生时:

java.lang.NullPointerException at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:569) at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211) at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1281) at android.view.View.dispatchRestoreInstanceState(View.java:12043) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2688) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694) at android.view.View.restoreHierarchyState(View.java:12021) at android.support.v4.app.Fragment.restoreViewState(Fragment.java:425) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:949) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440) at android.os.Handler.handleCallback(Handler.java:615) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4800) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565) at dalvik.system.NativeStart.main(Native Method) 

我可以以任何其他方式在子片段中使用ViewPager,但是如果我手动添加/删除子片段并在子片段中使用FragmentStatePagerAdapter,则无法工作。

下面的例子应该工作,但它不…我已经添加了一些解决了一些问题的代码,但它并没有解决所有问题…

 import java.lang.reflect.Field; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.TextView; public class TestActivity extends FragmentActivity implements OnClickListener { private Fragment fragment1; private Fragment fragment2; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_main); fragment1 = getSupportFragmentManager().findFragmentByTag("fragment1"); fragment2 = getSupportFragmentManager().findFragmentByTag("fragment2"); } @Override public void onClick(View v) { Fragment nextFragment = null; String nextFragmentTag = null; if (v.getId() == R.id.button1) { if (fragment1 == null) fragment1 = ContainerFragment.newInstance(1); nextFragment = fragment1; nextFragmentTag = "fragment1"; } else if (v.getId() == R.id.button2) { if (fragment2 == null) fragment2 = ContainerFragment.newInstance(2); nextFragment = fragment2; nextFragmentTag = "fragment2"; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.main, nextFragment, nextFragmentTag); transaction.addToBackStack(null); transaction.commit(); } public static class MainPagerAdapter extends FragmentStatePagerAdapter { public int button; public MainPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { return SubFragment.newInstance(button, i); } @Override public int getCount() { return 10; } } public static class ContainerFragment extends Fragment { static ContainerFragment newInstance(int pos) { ContainerFragment f = new ContainerFragment(); Bundle args = new Bundle(); args.putInt("pos", pos); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.view_pager, container, false); ViewPager pager = (ViewPager) rootView.findViewById(R.id.pager); MainPagerAdapter adapter = new MainPagerAdapter(getChildFragmentManager()); adapter.button = getArguments().getInt("pos"); pager.setAdapter(adapter); return rootView; } // --------------------------------------------------------------- // HACK FIX für java.lang.IllegalStateException: No activity // --------------------------------------------------------------- private static final Field sChildFragmentManagerField; static { Field f = null; try { f = android.support.v4.app.Fragment.class.getDeclaredField("mChildFragmentManager"); f.setAccessible(true); } catch (NoSuchFieldException e) { } sChildFragmentManagerField = f; } @Override public void onDetach() { super.onDetach(); if (sChildFragmentManagerField != null) { try { sChildFragmentManagerField.set(this, null); } catch (Exception e) { } } } } public static class SubFragment extends Fragment { static SubFragment newInstance(int button, int pos) { SubFragment f = new SubFragment(); Bundle args = new Bundle(); args.putString("key", "Button " + button + "Fragment " + pos); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.test_subfragment, container, false); ((TextView) rootView.findViewById(R.id.tv1)).setText(getArguments().getString("key")); return rootView; } } } 

为了完整起见,我还添加了xml文件:

test_main.xml

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button1" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button2" /> </LinearLayout> </FrameLayout> 

test_subfragment.xml

 <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv1" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="50sp" /> 

view_pager.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/llContainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> 

Related of "Fragment和FragmentStatePagerAdapter中的ViewPager片段导致exception(具有完整的示例)"

添加一个额外的FrameLayout到你的主要活动的布局 。 这是你放置片段的地方。

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button1" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button2" /> <!-- add this --> <FrameLayout android:id="@+id/fragment_frame" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> </LinearLayout> </FrameLayout> 

由于您正在将碎片添加到BackStack因此不需要保存它们的实例 。 这就是为什么你的应用程序崩溃的原因。 调整你的onClick()方法如下:

  @Override public void onClick(View v) { Fragment nextFragment = null; String nextFragmentTag = null; if (v.getId() == R.id.button1) { nextFragment = ContainerFragment.newInstance(1); nextFragmentTag = "fragment1"; } else if (v.getId() == R.id.button2) { nextFragment = ContainerFragment.newInstance(2); nextFragmentTag = "fragment2"; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.fragment_frame, nextFragment, nextFragmentTag); transaction.addToBackStack(null); transaction.commit(); } 

我testing了代码。 使用button更改碎片,并保留ViewPager留下的状态