使用 getChildFragmentManager().beginTransaction() 时的空对象引用
Posted
技术标签:
【中文标题】使用 getChildFragmentManager().beginTransaction() 时的空对象引用【英文标题】:Null object reference when using getChildFragmentManager().beginTransaction() 【发布时间】:2017-12-02 15:01:25 【问题描述】:我的 ViewPgaer 中有 4 个使用 FragmentPagerAdapter 的片段。我尝试在不断延迟后添加每个片段,以便在切换底部栏选项卡时获得无抖动动画。
我使用this 库作为具有移动动画的底栏。所有四个片段都有多个 api 调用,如果我在延迟后不添加这些,则移动动画很生涩。
问题是我收到了一个难以复制的错误日志(发布在下面)。
错误日志:
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:380)
at android.support.v4.app.BackStackRecord.add(BackStackRecord.java:369)
at com.vanitee.services.view.FragmentFake$1.run(FragmentFake.java:46)
at android.os.Handler.handleCallback(Handler.java:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6585)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831)
ViewPagerAdapterClass:
class MyAccountPagerAdapter extends FragmentPagerAdapter
public MyAccountPagerAdapter(FragmentManager fm)
super(fm);
@Override
public Fragment getItem(int position)
if (position == ME_TAB)
if (Utility.isEmpty(fragmentProfile))
fragmentProfile = FragmentFake.create(new FragmentUserProfile(), 50);
return fragmentProfile;
else if (position == BOOKINGS_TAB)
if (Utility.isEmpty(fragmentBooking))
fragmentBooking = FragmentFake.create(new FragmentBookings(), 100);
return fragmentBooking;
else if (position == WALLET_TAB)
if (Utility.isEmpty(fragmentWallet))
fragmentWallet = FragmentFake.create(new FragmentWallet(), 150);
return fragmentWallet;
else if (position == LIKES_TAB)
if (Utility.isEmpty(fragmentLikes))
fragmentLikes = FragmentFake.create(new FragmentLikes(), 200);
return fragmentLikes;
return null;
@Override
public CharSequence getPageTitle(int position)
switch (position)
case ME_TAB:
return getContext().getString(R.string.me_tab);
case BOOKINGS_TAB:
return getContext().getString(R.string.bookings_tab);
case WALLET_TAB:
return getContext().getString(R.string.wallet_tab);
case LIKES_TAB:
return getContext().getString(R.string.likes_tab);
default:
return null;
@Override
public int getCount()
return 4;
FragmentFake:
public class FragmentFake extends Fragment
private View root;
Fragment fragment;
public static Fragment create(Fragment frag, int timeMs)
FragmentFake fragmentFake = new FragmentFake();
Bundle bundle = new Bundle();
fragmentFake.fragment = frag;
bundle.putInt("time", timeMs);
fragmentFake.setArguments(bundle);
return fragmentFake;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
root = inflater.inflate(R.layout.layout_fake_fragment, container, false);
Bundle bundle = getArguments();
replaceFragment(bundle.getInt("time"));
return root;
private void replaceFragment(int time)
root.postDelayed(new Runnable()
@Override
public void run()
if(!isAdded())
return;
getChildFragmentManager().beginTransaction().add(R.id.replace_fragment_container, fragment).commit();
, time);
报错日志就行了
getChildFragmentManager().beginTransaction().add(R.id.replace_fragment_container, fragment).commit();
【问题讨论】:
在 beginTransation() 之前检查片段中的 getactivity() !=null。 你是救世主!但问题不是因为活动为空,我在事务中添加了一个空片段!不管怎样,你节省了我的时间 【参考方案1】:创建一个扩展片段的抽象片段。像这样
public abstract BaseChildFragment extends Fragment
public void onViewPagerPagechange();
使所有 ChildFragment 扩展 BaseChildFragment(FragmentUserProfile, FragmentUserLike,FragmentUserWellet,ETC) , 在您的适配器上添加以下代码。
LruCache<Integer,BaseChildFragment> cache = new LruCache<>(4);
public BaseChildFragment getBaseChildFragment(int position)
return cache.get(position);
@Override
public Fragment getItem(int position)
if (position == ME_TAB)
if (Utility.isEmpty(fragmentProfile))
fragmentProfile = FragmentFake.create(new FragmentUserProfile(), 50);
cache.put(position,fragmentProfile );
return fragmentProfile;
else if (position == BOOKINGS_TAB)
if (Utility.isEmpty(fragmentBooking))
fragmentBooking = FragmentFake.create(new FragmentBookings(), 100);
cache.put(position,fragmentBooking );
return fragmentBooking;
else if (position == WALLET_TAB)
if (Utility.isEmpty(fragmentWallet))
fragmentWallet = FragmentFake.create(new FragmentWallet(), 150);
cache.put(position,fragmentWallet );
return fragmentWallet;
else if (position == LIKES_TAB)
if (Utility.isEmpty(fragmentLikes))
fragmentLikes = FragmentFake.create(new FragmentLikes(), 200);
cache.put(position,fragmentLikes );
return fragmentLikes;
return null;
在您的 Fragment 上具有像这样的 View pager AddpageChangeListener
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener()
// optional
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
// optional
@Override
public void onPageSelected(int position)
BaseChildFragment fragment = adapter.getBaseChildFragment(position);
fragmeng.onViewPagerPagechange();
// optional
@Override
public void onPageScrollStateChanged(int state)
);
这将调用您的 ChildFragment onViewPagerPagechange();
方法。您可以在其中加载您的子片段。
【讨论】:
【参考方案2】:你不能这样做
public static Fragment create(Fragment frag, int timeMs)
FragmentFake fragmentFake = new FragmentFake();
Bundle bundle = new Bundle();
//remove this line, it won't work
fragmentFake.fragment = frag;
bundle.putInt("time", timeMs);
fragmentFake.setArguments(bundle);
return fragmentFake;
您可以从 create 语句中删除该分配行,并在创建实例后添加另一个方法来分配片段。你的代码应该是这样的
public static Fragment create(Fragment frag, int timeMs)
FragmentFake fragmentFake = new FragmentFake();
Bundle bundle = new Bundle();
bundle.putInt("time", timeMs);
fragmentFake.setArguments(bundle);
return fragmentFake;
public void setFragment(Fragment fragment)
this.fragment = fragment;
//How you assign fragment
FragmentFake fakeFragment = FragmentFake.create(0);
fakeFragment.setFragment(yourFragment);
然后进行分片交易
【讨论】:
但是实例是在分配片段之前创建的。你能告诉我它是如何解决这个问题的吗?因为这个问题不经常发生,我不知道如何复制它。以上是关于使用 getChildFragmentManager().beginTransaction() 时的空对象引用的主要内容,如果未能解决你的问题,请参考以下文章
Android Fragment使用 嵌套Fragments (Nested Fragments) 的使用及常见错误
Android Fragment使用 嵌套Fragments (Nested Fragments) 的使用及常见错误