使用 getChildFragmentManager().beginTransaction() 时的空对象引用
Null object reference when using getChildFragmentManager().beginTransaction()
我使用 FragmentPagerAdapter 在我的 ViewPgaer 中有 4 个片段。我尝试在持续延迟后添加每个片段,以便在切换底部栏选项卡时获得无抖动的动画。
我将 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.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();
你不能这样做
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);
然后进行分片交易
创建一个扩展片段的抽象片段。像这样
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();
方法。您可以在其中加载您的子片段。
我使用 FragmentPagerAdapter 在我的 ViewPgaer 中有 4 个片段。我尝试在持续延迟后添加每个片段,以便在切换底部栏选项卡时获得无抖动的动画。
我将 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.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();
你不能这样做
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);
然后进行分片交易
创建一个扩展片段的抽象片段。像这样
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();
方法。您可以在其中加载您的子片段。