来自 viewpager getActivity 的 Android childfragments 返回 null

标签 android android-activity android-fragments nullpointerexception

我有一个 Activity ,我用一个按钮在两个 fragment (主要和设置)之间切换。在 MAIN fragment 中,我有一个包含 4 个子 fragment 的 ViewPager

起初运行一切正常,但如果我旋转屏幕,ViewPager 中 fragment 的 getActivity() 返回 null。

ActivityMain:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // Add or show the fragments
    showHideScreenFragment(FRAGMENT_MAIN);
}

private void showHideScreenFragment(String tag) {   

    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    
    ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
    
    // Get the fragment from the backstack if it is existing
    BaseFragment oldFragment = getFragmentFromBackstack(tag);

    // Get the current fragment from the layout
    BaseFragment currentFragment = getCurrentFragment();
    
    if (oldFragment == null) {
        if (currentFragment != null) {
             ft.hide(currentFragment);
        }
        
        ft.add(getMainContainerId(), getFragmentInstance(tag), tag);
    }
    else {

        if (currentFragment != null) {
            if (isSameFragment(oldFragment, currentFragment))
                return;
            
            ft.hide(currentFragment);
        }
        
        if (oldFragment.isHidden())
            ft.show(oldFragment);
    }
        
    ft.commit();
    fm.executePendingTransactions();
}

private BaseFragment getFragmentInstance(String tag) {
    if (tag.equals(FRAGMENT_MAIN)) return getFragmentMain();
    if (tag.equals(FRAGMENT_SETTINGS)) return getFragmentSettings();
    
    throw new RuntimeException("Fragment not found !");
}

private FragmentMain getFragmentMain() {
    return new FragmentMain();
}

private FragmentSettings getFragmentSettings() {
    return new FragmentSettings();
}

private BaseFragment getFragmentFromBackstack(String tag) {
    if (tag.equals(FRAGMENT_MAIN)) return getFragmentMainFromBackstack();
    if (tag.equals(FRAGMENT_SETTINGS)) return getFragmentSettingsFromBackstack();
    
    throw new RuntimeException("Fragment not found !");
}

private FragmentMain getFragmentMainFromBackstack() {
    return (FragmentMain) getSupportFragmentManager().findFragmentByTag(FRAGMENT_MAIN);
}

private FragmentSettings getFragmentSettingsFromBackstack() {
    return (FragmentSettings) getSupportFragmentManager().findFragmentByTag(FRAGMENT_SETTINGS);
}

private boolean isSameFragment(Fragment f1, Fragment f2) {
    return f1.getTag().equals(f2.getTag());
}

FragmentMain:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {         
        View view = inflater.inflate(R.layout.fragment_main, container, false);
        
        viewPager = (ViewPager) view.findViewById(R.id.viewPager);
        
        // Add the 4 child fragments to the viewpager
        populateViewPager();
        
        // Debugging
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                _printFragmentStates();
            }
        }, 2500);
        
        return view;
    }

    private void populateViewPager() {      
        ArrayList<BaseMainFragment> fragments = new ArrayList<BaseMainFragment>();
        
        fragments.add(new FragmentSearch());
        fragments.add(new FragmentFavorites());
        fragments.add(new FragmentHouse());
        fragments.add(new FragmentRoom());
        
        adapterMain = new AdapterMain(getChildFragmentManager(), fragments);
        
        viewPager.setOffscreenPageLimit(4);
        viewPager.setAdapter(adapterMain);
    }

    // DEBUGGING
    private void _printFragmentStates() {
        Activity actSearch = null;
        Activity actFav = null;
        Activity actHouse = null;
        Activity actRoom = null;
    
        actSearch = getFragmentSearch().getActivity();
        actFav = getFragmentFavorites().getActivity();
        actHouse = getFragmentHouse().getActivity();
        actRoom = getFragmentRoom().getActivity();
    
        Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        Functions.logd("Main fragment act, is null: " + (getActivity() == null));
        Functions.logd("Search act, is null: " + (actSearch == null));
        Functions.logd("Favorite act, is null: " + (actFav == null));
        Functions.logd("House act, is null: " + (actHouse == null));
        Functions.logd("Room act, is null: " + (actRoom == null));
        Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        Functions.logd("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}

private FragmentSearch getFragmentSearch() {
    return (FragmentSearch) adapterMain.getItem(0);
}

private FragmentFavorite getFragmentFavorite() {
    return (FragmentFavorite) adapterMain.getItem(1);
}

private FragmentHouse getFragmentHouse() {
    return (FragmentHouse) adapterMain.getItem(2);
}

private FragmentRoom getFragmentHouse() {
    return (FragmentRoom) adapterMain.getItem(3);
}

正如我所说,起初运行一切正常,但在我旋转屏幕后,我在 4 个子 fragment 中的 getActivity(); 得到空值:Search、Favorite、House 和 Room .

Logcat 调试

1 次运行:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Main fragment act, is null: false
Search act, is null: false
Favorite act, is null: false
House act, is null: false
Room act, is null: false
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

屏幕方向改变后:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Main fragment act, is null: false
Search act, is null: true
Favorite act, is null: true
House act, is null: true
Room act, is null: true
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我做错了什么?

最佳答案

经过几个小时的调试,我发现如果您只有 1 个 fragment (没有子 fragment 或嵌套 fragment )附加到您的 Activity ,那么您不需要重新添加 fragment 。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Add or show the fragments if the savedInstance is null, otherwise let the system reattach your fragment.
    if (savedIstance == null)
       showHideScreenFragment(FRAGMENT_MAIN);
}

你不需要重新附加 fragment ,android系统会为你做这件事。

而子 fragment 中getActivity();获取NPE的解决方案是:

使用 FragmentStatePagerAdapter 作为您的 ViewPager 的适配器。

并覆盖保存的状态方法:

@Override
public Parcelable saveState() {
    return null;
}

我不知道为什么,但是 setRetainInstance(false); 对我没有帮助,我认为这对我来说仍然是个谜。

关于来自 viewpager getActivity 的 Android childfragments 返回 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26671390/

相关文章:

android - 删除 fragment 时崩溃

java - NullPointerException - 无法启动 Activity

android - Android 中 Onclick 上带有 bool 值的图像

android - 删除保存的 ListView 中的所有内容,并在每次更新时递增 1

java - 如何将大个人资料图片添加到我的抽屉导航中?

android - onResume() 仅当应用程序通过启动器图标启动时才起作用,而不是在安装时按打开按钮

java - 如何在所有 Activity 中显示一个 fragment

android - java.lang.RuntimeException : Unable to start activity ComponentInfo Make sure to call FirebaseApp. initializeApp(Context) 首先

android - Activity 选择器菜单问题 : Dialing a number

android - 将焦点从 ViewPager/TabLayout 中的选项卡移开