来自viewpager getActivity的Android childfragments返回null

Zba*_*ian 5 android nullpointerexception android-fragments android-activity

我有一个活动和一个按钮,我在两个片段之间切换(MAIN&SETTINGS).在MAIN片段中,我有ViewPager4个子片段.

在第一次运行时一切正常,但如果我旋转屏幕,其中getActivity()的片段ViewPager返回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());
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

正如我所说,在第一次运行时一切正常,但在我旋转屏幕后,我getActivity();在4个子片段中得到null :搜索,收藏,房子和房间.

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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

屏幕方向改变后:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Rak*_*ari 0

使用片段时遵循这样的模式是一个很好的做法:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    view = view.findViewById(R.id.view);
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
// do your thing here
populateViewPager();
}
Run Code Online (Sandbox Code Playgroud)

1) 用于OnCreateView设置片段的视图,2)OnViewCreated初始化视图,3)OnActivityCreated设置事物。

使用getActivity()insideOnActivityCreated可确保getActivity()不会返回 null。仅在活动完全初始化后才会调用此方法。OnAttach, OnCreate,OnCreateView可能会在活动创建之前得到。