【问题标题】:Android childfragments from viewpager getActivity returns null来自 viewpager getActivity 的 Android 子片段返回 null
【发布时间】:2014-12-27 13:54:57
【问题描述】:

我有一个活动,并通过一个按钮在两个片段(主要和设置)之间切换。在 MAIN 片段中,我有一个带有 4 个子片段的 ViewPager

第一次运行一切正常,但如果我旋转屏幕,ViewPager 中的片段的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);
}

正如我所说,起初运行一切正常,但在我旋转屏幕后,getActivity(); 在 4 个子片段中为空:搜索、收藏夹、房屋和房间。

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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我做错了什么?

【问题讨论】:

    标签: android android-activity android-fragments nullpointerexception


    【解决方案1】:

    经过数小时的调试,我发现如果您的活动只有 1 个片段(没有子片段或嵌套片段),那么您不需要重新添加片段。

    @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系统会为你做这个。

    在子片段中获取NPE getActivity(); 的解决方案是:

    使用FragmentStatePagerAdapter 作为ViewPager 的适配器。

    并覆盖保存状态方法:

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

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

    【讨论】:

      【解决方案2】:

      在处理片段时遵循这样的模式是一个好习惯:

      @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();
      }
      

      1) 使用OnCreateView 设置片段的视图, 2) OnViewCreated 初始化视图和 3)OnActivityCreated 进行设置。

      OnActivityCreated 中使用getActivity() 可确保getActivity() 不返回null。只有在活动完全初始化后才会调用此方法。 OnAttachOnCreateOnCreateView 甚至可能在活动创建之前得到。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-30
        • 2017-05-05
        • 2014-02-03
        • 1970-01-01
        • 2012-07-22
        • 2012-07-25
        • 1970-01-01
        相关资源
        最近更新 更多