精华内容
下载资源
问答
  • fragment嵌套fragment
    2021-06-07 17:33:43

    当前位置:我的异常网» Android » Android使用Fragment嵌套Fragment的模式实现界面滑动

    Android使用Fragment嵌套Fragment的模式实现界面滑动

    www.myexceptions.net  网友分享于:2014-01-13  浏览:642次

    Android使用Fragment嵌套Fragment的方式实现界面滑动

    // 主Activity

    public class HomeActivity extends FragmentActivity implements OnClickListener {

    private TextView footerLeft;

    private TextView footerMiddle;

    private TextView footerRight;

    private Context context;

    private FragmentManager fragmentManager;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.home_activity);

    initArgs();

    getView2Init();

    initFragment(new Fragment1());

    }

    /**

    * 初始化变量

    */

    private void initArgs() {

    context = HomeActivity.this;

    fragmentManager = getSupportFragmentManager();

    }

    /**

    * 获得布局文件上的控件并初始化

    */

    private void getView2Init() {

    // 获得控件View

    footerLeft = (TextView) findViewById(R.id.tv_footer_left);

    footerMiddle = (TextView) findViewById(R.id.tv_footer_middle);

    footerRight = (TextView) findViewById(R.id.tv_footer_right);

    // 初始化控件View

    footerLeft.setOnClickListener(this);

    footerMiddle.setOnClickListener(this);

    footerRight.setOnClickListener(this);

    }

    @Override

    public void onClick(View v) {

    // 当footer中的三个文本控件被点击时,作出回应

    if (v == footerLeft) {

    Toast.makeText(context, "点击了底栏left左边按钮", Toast.LENGTH_SHORT).show();

    updateFragment(new Fragment1(), false);

    } else if (v == footerMiddle) {

    Toast.makeText(context, "点击了底栏middle中间按钮", Toast.LENGTH_SHORT).show();

    updateFragment(new Fragment2(), false);

    } else if (v == footerRight) {

    Toast.makeText(context, "点击了底栏Right右边按钮", Toast.LENGTH_SHORT).show();

    updateFragment(new Fragment3(), false);

    }

    }

    /**

    * 初始化Fragment

    *

    * @param f

    */

    private void initFragment(Fragment f) {

    updateFragment(f, true);

    }

    /**

    * 更新Fragment

    *

    * @param f

    * @param isInit

    */

    private void updateFragment(Fragment f, boolean isInit) {

    FragmentTransaction ft = fragmentManager.beginTransaction();

    ft.replace(R.id.content, f);

    ft.commit();

    }

    }

    // 用来实现切换的Adapter

    public class MyPagerAdapter1 extends FragmentStatePagerAdapter {

    protected static final String[] SUB_FRAGMENT = new String[] { "Fragment1_1", "Fragment1_2",

    "Fragment1_3" }; // 对应于每个大Fragment的小Fragment

    private int mCount = SUB_FRAGMENT.length;

    public MyPagerAdapter1(FragmentManager fm) {

    super(fm);

    }

    @Override

    public Fragment getItem(int position) {

    if (0 == position) {

    return new Fragment1_1();

    } else if (1 == position) {

    return new Fragment1_2();

    } else if (2 == position) {

    return new Fragment1_3();

    } else {

    System.out.println("创建子Fragment1_" + position + "失败");

    return null;

    }

    }

    @Override

    public int getCount() {

    return mCount;

    }

    @Override

    public CharSequence getPageTitle(int position) {

    return SUB_FRAGMENT[position % mCount];

    }

    }

    // 主Activity下有三个一级Fragment,这是其中之一

    public class Fragment1 extends Fragment {

    private MyPagerAdapter1 mAdapter;

    private ViewPager mPager;

    private TitlePageIndicator mIndicator;

    private static int mCurrentSubFragmentSeq = 0;

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setRetainInstance(true);

    }

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.fragment1, container, false);

    System.out.println("F1:onCreateView");

    mAdapter = new MyPagerAdapter1(getFragmentManager());

    mPager = (ViewPager) v.findViewById(R.id.pager);

    mPager.setAdapter(mAdapter);

    mIndicator = (TitlePageIndicator) v.findViewById(R.id.titles);

    mIndicator.setViewPager(mPager, mCurrentSubFragmentSeq);

    System.out.println("2、mCurrent Sub Fragment Sequence: " + mCurrentSubFragmentSeq);

    mIndicator.setFooterIndicatorStyle(IndicatorStyle.Triangle);

    mIndicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

    @Override

    public void onPageSelected(int position) {

    System.out.println("Changed to page " + position);

    mCurrentSubFragmentSeq = position;

    }

    @Override

    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override

    public void onPageScrollStateChanged(int state) {

    }

    });

    return v;

    }

    @Override

    public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    }

    }

    // 每个一级Framgment下面有三个二级Fragment,这是其中之一

    public class Fragment1_1 extends Fragment {

    private static final String KEY_CONTENT = "Fragment1:Content";

    private Bundle bundle;

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {

    bundle = savedInstanceState.getBundle(KEY_CONTENT);

    }

    }

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.fragment1_1, container, false);

    return v;

    }

    @Override

    public void onSaveInstanceState(Bundle outState) {

    super.onSaveInstanceState(outState);

    outState.putBundle(KEY_CONTENT, bundle);

    }

    }

    文章评论

    更多相关内容
  • 1.fragment嵌套fragment时出现getActivity()为null  activity A嵌套fragment B,B嵌套fragment C,C跳转到activity D,当activity D被finish掉之后,C中容易爆出getActivity为空.如果你的activity被回收了,那你需要在...
  • fragment嵌套fragment

    2016-08-23 14:30:22
    fragment嵌套fragment
  • Fragment嵌套Fragment实现多tab页面

    千次下载 热门讨论 2016-03-16 08:04:09
    原来做的一个练手的项目,里面主要是Fragment嵌套,需要的朋友可以看下,如果遇到不能运行的状况可酌量删除些代码。
  • Fragment嵌套Fragment

    千次阅读 2019-04-01 12:57:45
    问题1、fragment嵌套fragment不显示问题 通常时候,我们制作底部Tab切换,会用到fragment。即一个Activity下,使用4种fragment。这次遇到的问题是关于fragment再次嵌套fragmen的问题,功能需要在其中一个fragment中...

    问题1、fragment嵌套fragment不显示问题

    通常时候,我们制作底部Tab切换,会用到fragment。即一个Activity下,使用4种fragment。这次遇到的问题是关于fragment再次嵌套fragmen的问题,功能需要在其中一个fragment中再次嵌套frament,使用viewPager嵌套,此时需要注意一点,使用viewpager包裹住子fragment,我们都知道viewpager需要传入一个adapter,而此adaper需要一个fragmentManager,注意了!!!!!!这个fragmentManager必须是getChildFragmentManager。不能使用mActivity.getSupportFragmentManager()。造成的后果就是不显示问题了,关键是没有任何报错信息,一开始着实困扰了我好一阵子。

     

    关于getChildFragmentManager和getSupportFragmentManager的区别:

    首先需要知道一点:getSupportFragmentManager是在v4包下的,如果不是v4包下的,则称getFragmentManager。

    我们先看getChildFragment的源码是怎么解释他的:

    返回一个私有的管理器manager,该manager用于放置和管理子fragment。即getSupportFragmentManager获取到的是当前fragment的下一级的fragments的管理器。

    getSupportFragmentManager的源码解释:

    getFragmentManager也是一样的。 返回与此activity相关联交互的manager。即返回的是activity下的管理器,用于管理activity下与之相关联的fragent。

    如果我们在父fragmen中调用getFragmentManager或者getSupportFragmentManager,返回的是activity下的manager,即把自己添加进来的manager。这就是上文提到的frag不显示的问题所在。

    额外小栗子:加入FragmentA下有一个子FragmentB,(A包含B)。fragmentB调用getFragmentManager,得到的是fragmentA下的manager,即得到的是A调用的getChildFragmentManager。

    结论:getFragmentManager()是本级别管理者, getChildFragmentManager()是下一级别管理者.

     

     

    问题2、子fragment嵌套在xml文件中

    官网中有这么一句话;

    Note: You cannot inflate a layout into a fragment when that layout includes a <fragment>.
    Nested fragments are only supported when added to a fragment dynamically.

     简单来说,fragment不能写死在某个Fragment的xml文件中,fragment只能支持动态的添加进另一个fragment中。

    如果Fragment被嵌套写在了布局里, inflate到这个标签的时候就相当于将它加进了FragmentManager里.
    如果嵌套的parent fragment因为需要重建View而重新走了onCreateView()方法, 再次inflate, 此时就会抛出异常: InflateException in Binary XML

    之前为什么可以呢? 非嵌套的情况, fragment直接加在activity里, 如果需要重新inflate, 必定是在onCreate()里, activity是重新建的, 所以没有问题, 因为不存在fragmentManager中已经持有同一个fragment的问题.

    举一个例子:
    在嵌套的情况下, 如果FragmentE布局里有FragmentA, 这时候我们需要叠加一个FragmentD.
    用了replace(), 并且addToBackStack().
    当D显示的时候, E实际上View是被销毁的, 然后back回来, 重建View, 即FragementE需要重新从onCreateView
    ()开始走生命周期, 走到inflate的时候又看到了fragmentA的标签.
    但是这时候A实际上还在FragmentManager里面, 所以就会抛出如下的异常:
    android.view.InflateException: Binary XML file line # XX: Binary XML file line #XX: Error inflating class fragment
    崩溃的位置就在parent fragment(FragmentE) inflate的时候.

     

    问题3、把fragment放在一个动态布局里

    把fragment放在一个动态布局里 -> java.lang.IllegalArgumentException: No view found for id

    发现这个错误是因为项目中的一个子Fragment是添加在RecyclerView里面的一块的.
    RecyclerView要等到Loader的数据取到了之后再populate每一块的布局.
    还是上面的流程, 启动父fragment, load数据, 添加子fragment, 这都没有问题.
    但是一旦如果是上面的replace()addToBackStack() , 并且再次返回, 就会出现异常.

    因为当重建View的时候, fragmentManager其中是持有child fragment的, 但是找不到它的container, 于是就会抛出异常.
    栗子:
    在Fragment F中, 先添加一个FrameLayout, 再把child fragment A加进去.
    然后在Activity中, 用D replace F, 按back键返回, 就会有crash:

         java.lang.IllegalArgumentException: No view found for id 0x7f0c0062 (com.example.ddmeng.helloactivityandfragment:id/frame_container) for fragment FragmentA{b37763 #0 id=0x7f0c0062 FragmentA}
             at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:965)
             at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
             at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1130)
             at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1953)
             at android.app.Fragment.performActivityCreated(Fragment.java:2234)
             at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:992)
             at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
             at android.app.BackStackRecord.popFromBackStack(BackStackRecord.java:1670)
             at android.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1587)
             at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:578)
             at android.app.Activity.onBackPressed(Activity.java:2503)

    这是因为返回的时候FragmentManager找不到对应的container了.
    所以应该避免这种做法, 尽量把fragment加进parent的根布局里, 而不是某个动态添加的布局.

    补充

    1.推荐使用v4包下的fragment,兼容性更强

    2.除了上面提到的viewpager中添加fragment,还可以动态的添加fragment。此时需要用到的也是getChildFragmentManager

            Fragment fragment = new CharFrag();
            FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
            transaction.add(R.id.charXXXX_fragment, fragment).commit();

     对于其内部的子fragment,比如这里的CharFrag,可以使用getParentFragment()方法获取到宿主fragment。

    参考:https://www.cnblogs.com/mengdd/p/5552721.html

     

    展开全文
  • 自从Android3.0引入了Fragment之后,使用Activity去嵌套一些Fragment的做法也变得更加流行,这确实是Fragment带来的一些优点,比如说:Fragment可以使你能够将activity分离成多个可重用的组件,每个都有它自己的生命...
  • viewPager + fragment实现基础的页面滑动效果,Fragment+Fragment实现滑动
  • 由于项目要改成MVP模式,自然会用到了Fragment,有时候可能会需要一个Fragment里面嵌套多个Fragment,并且add完成后需要立即刷新子Fragment的View,那么这个时候就会抛出异常,先看一段代码:MainActivity.java@...

    由于项目要改成MVP模式,自然会用到了Fragment,有时候可能会需要一个Fragment里面嵌套多个Fragment,并且add完成后需要立即刷新子Fragment的View,那么这个时候就会抛出异常,先看一段代码:

    MainActivity.java

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    setContentView(R.layout.activity_main);

    //省略逻辑代码。。。

    mMessageFragment = MessageFragment.newInstance();

    getSupportFragmentManager()

    .beginTransaction().add(R.id.layout_activity_main_fragment_contianer, mMessageFragment)

    .commitAllowingStateLoss();

    }

    MessageFragment.java

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.fragment_message, null);

    ButterKnife.bind(this, rootView);

    return rootView;

    }

    @Override

    public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    initFragment();

    updateFragment();

    }

    private void updateFragment(){

    for(int i=0;i

    mMessageFragments[i].update();

    }

    }

    private void initFragment() {

    replyFragment = ConversationListFragment.newInstance(false);

    replyFragment);

    privateFragment = ConversationListFragment.newInstance(true);

    privateFragment);

    mMessageFragments = new Fragment[]{ replyFragment, privateFragment};

    getChildFragmentManager()

    .beginTransaction()

    .add(R.id.fragment_container, replyFragment)

    .add(R.id.fragment_container, privateFragment)

    .hide(privateFragment)

    .show(replyFragment)

    .commitAllowingStateLoss();

    }

    ConversationListFragment.java

    public static ConversationListFragment newInstance(boolean isprivate) {

    ConversationListFragment fragment = new ConversationListFragment();

    Bundle args = new Bundle();

    args.putBoolean("isprivate", isprivate);

    fragment.setArguments(args);

    return fragment;

    }

    @Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    if (getArguments() != null) {

    mIsPrivate = getArguments().getBoolean("isprivate");

    }

    }

    @Nullable

    @Override

    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_message_conversation_list, null);

    ButterKnife.bind(this, view);

    return view;

    }

    public void update(){

    //当代码运行到这里的时候就会发生错误

    //比如:mIsPrivated的值是默认值,并没有获取到外部传过来的值,如果逻辑代码中需要用到View,则还会抛出空指针异常!

    if(mIsPrivated){

    //省略逻辑。。。

    }else{

    //省略逻辑。。。

    }

    }

    分析原因

    相信只要仔细看过上面的代码的都应该明白错误的原因了,主要原因就是对Fragment生命周期了解的不够透彻,因为在父Fragment的onActivityCreated方法中虽然实例化了子Fragment但是子Fragment的生命周期方法并没有被调用,所以这个时候子Fragment的View还没有被创建,如果直接在父Fragment的onActivityCreated方法中调用子Fragment更新View的方法就会抛出异常!

    解决方案

    既然知道了是因为子Fragment生命周期方法未执行引起的,那么就应该把更新子Fragmet的调用时机放到父Fragment的onActivCreated方法之外,可以放到父Fragment的onStart方法中即可!

    总结

    其实主要是对Fragment生命周期方法不熟造成的,再次回忆总结一下Fragment生命周期方法:

    58196b8116cf

    1354170699_6619.png

    Activity与Fragment对比图

    58196b8116cf

    1354170682_3824.png

    生命周期分析:

    ragment被创建的时候

    onAttach()

    onCreate()

    onCreateView()

    onActivityCreated()

    2.fragment对用户可见的时候

    onStart()

    onResume()

    fragment进入“后台模式”的时候

    onPause()

    onStop()

    fragment被销毁的时候

    onPause()

    onStop()

    onDestroyView()

    onDestroy()

    onDetach()

    就像activitie一样,在以下的状态中,可以使用Bundle对象保存一个fragment的对象。

    onCreate()

    onCreateView()

    onActivityCreated()

    fragments的大部分状态都和activitie很相似,但fragment有一些新的状态。

    onAttached() —— 当fragment被加入到activity时调用(在这个方法中可以获得所在的activity)。

    onCreateView() —— 当activity要得到fragment的layout时,调用此方法,fragment在其中创建自己的layout(界面)。

    onActivityCreated() —— 当activity的onCreated()方法返回后调用此方法

    onDestroyView() —— 当fragment中的视图被移除的时候,调用这个方法。

    onDetach() —— 当fragment和activity分离的时候,调用这个方法。

    展开全文
  • 嵌套Fragments (Nested Fragments), 是在Fragment内部又添加Fragment. 使用时, 主要要依靠宿主Fragment的getChildFragmentManager()来获取FragmentManger. 虽然看起来和在activity中添加fragment差不多, 但因为...

    嵌套Fragments (Nested Fragments), 是在Fragment内部又添加Fragment.
    使用时, 主要要依靠宿主Fragment的 getChildFragmentManager() 来获取FragmentManger.
    虽然看起来和在activity中添加fragment差不多, 但因为fragment生命周期及管理恢复模式不同, 其中有一些需要特别注意的地方.
    本文内容还包括了从Fragment迁移到v4.Fragment代码中需要改动的一些地方.

    嵌套Fragments

    嵌套Fragments Nested Fragments 是Android 4.2 API 17 引入的.
    目的: 进一步增强动态复用.
    如果要在Android 4.2之前使用, 可以用support library v4的版本, 后面会有详细的迁移过程介绍.

    嵌套Fragment的动态添加

    在宿主fragment里调用getChildFragmentManager()
    即可用它来向这个fragment内部添加fragments.

     
    
    Fragment videoFragment = new VideoPlayerFragment();
    FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
    transaction.add(R.id.video_fragment, videoFragment).commit();

    同样, 对于内部的fragment来说, getParentFragment() 方法可以获取到fragment的宿主fragment.

    getChildFragmentManager() 和 getFragmentManager()

    getChildFragmentManager()是fragment中的方法, 返回的是管理当前fragment内部子fragments的manager.
    getFragmentManager()在activity和fragment中都有.
    在activity中, 如果用的是v4 support库, 方法应该用getSupportFragmentManager(), 返回的是管理activity中fragments的manager.
    在fragment中, 还叫getFragmentManager(), 返回的是把自己加进来的那个manager.

    也即, 如果fragment在activity中, fragment.getFragmentManager()得到的是activity中管理fragments的那个manager.
    如果fragment是嵌套在另一个fragment中, fragment.getFragmentManager()得到的是它的parent的getChildFragmentManager().

    总结就是: getFragmentManager()是本级别管理者, getChildFragmentManager()是下一级别管理者.
    这实际上是一个树形管理结构.

    使用Support library

    为什么要使用support library? 有两种原因:

    1. 要在API level11之前使用fragment.
    2. 要在API Level 17之前使用getChildFragmentManager(), 即使用嵌套Fragment.

    迁移到support library需要改动哪些地方?

    把Fragment迁移到v4版本, 需要改动如下地方:

     
    
    import android.app.Fragment; -> import android.support.v4.app.Fragment;
    Activity -> FragmentActivity / AppCompatActivity
    activity.getFragmentManager() -> getSupportFragmentManager()
    Loader, LoaderManager, LoaderCursor也需要改成v4包的.
    activity.getLoaderManager() -> getSupportLoaderManager()

    Fragment中onTrimMemory()方法不见了
    以前是这个方法

     
    
    @Override
    public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    imageLoader.trimMemory(level);
    }

    v4版本需要改成这个

     
    
    @Override
    public void onLowMemory() {
    super.onLowMemory();
    imageLoader.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
    }

    嵌套Fragment使用常见错误

    错误情形1: 把嵌套Fragment放在布局里

    把嵌套Fragment放在布局里 -> InflateException in Binary XML

    看起来嵌套fragment的使用除了要用getChildFragmentManager()以外, 其他跟之前似乎没什么区别.
    如果嵌套的fragment不需要太多控制, 固定地占据了一块地方, 你可能想当然地为了省事就把它放进了xml布局文件里, 写个标签.
    运行一下初看起来似乎没什么错, run一下也能显示出来, 但是千万不要这样做, 多玩两下更复杂的你就知道了.

    上面官网介绍时就有这么一句:

     
    
    Note: You cannot inflate a layout into a fragment when that layout includes a <fragment>.
    Nested fragments are only supported when added to a fragment dynamically.

    人家这么说肯定是有原因的哇, 下面我来告诉你我知道的问题:
    如果Fragment被嵌套写在了布局里, inflate到这个标签的时候就相当于将它加进了FragmentManager里.
    如果嵌套的parent fragment因为需要重建View而重新走了onCreateView()方法, 再次inflate, 此时就会抛出异常:InflateException in Binary XML

    之前为什么可以呢? 非嵌套的情况, fragment直接加在activity里, 如果需要重新inflate, 必定是在onCreate()里, activity是重新建的, 所以没有问题, 因为不存在fragmentManager中已经持有同一个fragment的问题.

    举一个例子:
    在嵌套的情况下, 如果FragmentE布局里有FragmentA, 这时候我们需要叠加一个FragmentD.
    用了replace(), 并且addToBackStack().
    当D显示的时候, E实际上View是被销毁的, 然后back回来, 重建View, 即FragementE需要重新从onCreateView
    ()开始走生命周期, 走到inflate的时候又看到了fragmentA的标签.
    但是这时候A实际上还在FragmentManager里面, 所以就会抛出如下的异常:
    android.view.InflateException: Binary XML file line # XX: Binary XML file line #XX: Error inflating class fragment
    崩溃的位置就在parent fragment(FragmentE) inflate的时候.
    打印具体的异常栈信息可以看到:

     
    
    at com.example.ddmeng.helloactivityandfragment.fragment.FragmentE.onCreateView(FragmentE.java:35)
    at android.app.Fragment.performCreateView(Fragment.java:2220)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:973)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
    at android.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1587)
    at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:578)
    at android.support.v4.app.BaseFragmentActivityEclair.onBackPressedNotHandled(BaseFragmentActivityEclair.java:27)
    at android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity.java:189)
    Caused by: java.lang.IllegalArgumentException: Binary XML file line #16: Duplicate id 0x7f0c0059, tag null, or parent id 0xffffffff with another fragment for com.example.ddmeng.helloactivityandfragment.fragment.FragmentA
    at android.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2205)

    实验例子代码

    Solution 1: 动态添加child fragment

    解决上面的问题有各种方法, 最常规的做法是, 使用动态添加:

     
    
    Fragment fragmentA = getChildFragmentManager().findFragmentByTag(NESTED_FRAGMENT_TAG);
    if (fragmentA == null) {
    Log.i(LOG_TAG, "add new FragmentA !!");
    fragmentA = new FragmentA();
    FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
    fragmentTransaction.add(R.id.fragment_container, fragmentA, NESTED_FRAGMENT_TAG).commit();
    } else {
    Log.i(LOG_TAG, "found existing FragmentA, no need to add it again !!");
    }

    Solution 2: 在异常之前remove child fragment

    如果你的子fragment非要加在布局里不可, 而你的程序确实会有重建父fragment view的情形.
    为了避免上面的异常, 你也可以这样做(tricky and not recommended):

     
    
    public void removeChildFragment(Fragment parentFragment) {
    FragmentManager fragmentManager = parentFragment.getChildFragmentManager();
    Fragment child = fragmentManager.findFragmentById(R.id.child);
    if (child != null) {
    fragmentManager.beginTransaction()
    .remove(child)
    .commitAllowingStateLoss();
    }
    }

    在parentFragment的onCreateView()方法中inflate之前和onSaveInstanceState()方法中做save工作之前调用它.
    这两个地方是发生异常的地方, 只要在其之前remove就好.

    错误情形2: 把fragment放在一个动态布局里

    把fragment放在一个动态布局里 -> java.lang.IllegalArgumentException: No view found for id

    发现这个错误是因为项目中的一个子Fragment是添加在RecyclerView里面的一块的.
    RecyclerView要等到Loader的数据取到了之后再populate每一块的布局.
    还是上面的流程, 启动父fragment, load数据, 添加子fragment, 这都没有问题.
    但是一旦如果是上面的replace()addToBackStack() , 并且再次返回, 就会出现异常.

    因为当重建View的时候, fragmentManager其中是持有child fragment的, 但是找不到它的container, 于是就会抛出异常.
    我也同样做了一个小实验, 在我的demo程序里:
    HelloActivityAndFragment
    Nested Fragment in Dynamic Container:
    在Fragment F中, 先添加一个FrameLayout, 再把child fragment A加进去.
    然后在Activity中, 用D replace F, 按back键返回, 就会有crash:

     
    
    java.lang.IllegalArgumentException: No view found for id 0x7f0c0062 (com.example.ddmeng.helloactivityandfragment:id/frame_container) for fragment FragmentA{b37763 #0 id=0x7f0c0062 FragmentA}
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:965)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1130)
    at android.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1953)
    at android.app.Fragment.performActivityCreated(Fragment.java:2234)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:992)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
    at android.app.BackStackRecord.popFromBackStack(BackStackRecord.java:1670)
    at android.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1587)
    at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:578)
    at android.app.Activity.onBackPressed(Activity.java:2503)

    这是因为返回的时候FragmentManager找不到对应的container了.
    所以应该避免这种做法, 尽量把fragment加进parent的根布局里, 而不是某个动态添加的布局.

    其他

    关于嵌套fragments的情况, 可能和ViewPager结合使用的情形比较多.
     

    这里有个大哥写了个工具类Fragmentation.
    他也有几篇博文分析遇到的坑和原因(见上面repo的README给出的链接), 里面有一些back stack的问题, 还有动画什么的, 大家有兴趣可以看看.

    展开全文
  • fragment10 和fragment11 代码一模一样 , 但是 fragment 11 不能滑动 , 代码如下 public class Fragment10 extends Fragment { public static final String TAG = Fragment10.class.getSimpleName(); @BindView...
  • Android开发-Fragment嵌套Fragment

    千次阅读 2020-04-11 14:38:34
    Android开发-Fragment嵌套Fragment前言使用依赖远程仓库地址布局实现使用控件xml代码Java实现效果图项目地址 前言 在大多数公司中,他们会尽量少写Activity,多使用Fragment,使项目变成一个千层饼,在本文章中我会...
  • 今天在一个fragment里面嵌套了ViewPager,在ViewPager里面嵌套了3个Fragment,但是来回切换的时候,发现有的页面出现了空白,网上说是getChildFragmentManager()有问题,仔细排查以后,发现在使用fragment+viewpager加载...
  • 如有错误欢迎指正 上网搜的文章大都是通过activity将一个fragment导入一个fragment,但是我要的是用fragment控制导入一个fragment到自己布局中。在我自学的过程中遇到了很多疑惑... 我们先来看一下嵌套fragment的...
  • Fragment嵌套fragmen。对应的博客链接:http://blog.csdn.net/r_ine,其中有一篇是对其的介绍。这是一个 eclipse资源。
  • 在Activity中启动FragmentA,FragmentA嵌套FragmentB,在FragmentB中startActivityForResult,返回时FragmentA的onActivityResult并没有被调用,而调用了Activity中的onActivityResult。 解决方案 问题出在的...
  • 项目是fragment嵌套fragment,最初的时候在fragment viewpager中的第一个fragment中嵌套fragment viewpager 其他是fragment 没有什么问题,后边需求改变,在第一个fragment中嵌套的fragment viewpager 要移动到第三...
  • android 布局中Fragment嵌套Fragment

    万次阅读 2015-12-21 09:39:42
    在其中一个Fragment中,顶部有四个切换的按钮,需要再对应四个Fragment,这样就涉及到Fragment嵌套Fragment的问题 界面图 说一下设计思路 第一张图,三个切换按钮,分别是”附近“,”充电“,”我的“,先...
  • 使用场景分析:我们app的底部tab嵌套的是fragement 在这个fragment里边我们又嵌套了新的tab 来管理新的嵌套fragment 我们要在第一个fragment里边有按钮 点击之后 要刷新某一个fragment列表的数据,通常我们可以...
  • fragment嵌套fragment的通信

    千次阅读 2017-02-27 15:14:14
    嵌套Fragment里面的Fragment可以使用getParentFragment()函数获取到父窗口Fragment的实例,然后对其replace(替换)。 但是在外层Fragment添加内部fragment时要使用getChildFragmentManager(); ...
  • 我的项目目录如下: 直接上核心代码 MainActivity import android.support.v4.app.FragmentTransaction;...import android.support.v4.app.Fragment; import android.support.v4.app.FragmentAc
  • //首先创建fragment在MainActivity中和RadioGroup一起使用,之后再第一个Fragment中布局ViewPaegr 再ViewPager总添加Fragment,在布局ListView添加适配器即可,//fragment中嵌套子fragment要用getChildFragmentManager...
  • 如下图,父Fragment嵌套子Fragment在切换过程中部分子Fragment不显示。 解决方案 原来的子Fragment中FragmentPagerAdapter的初始化使用的是getFragmentManager() ... new FragmentPagerAdapter...
  • 今天遇到挺纠结的问题,由于产品设计的问题,技术上涉及到activity 嵌套一级fragment,一级fragment嵌套二级fragment,在一级fragment中刷新二级fragment中的UI。其中一级fragment中有顶部搜索栏,搜索栏下面有...
  • 实际管理相互独立的并且隶属于Activity的Fragment使用FragmentManager(),而在Fragment中动态的添加Fragment要使用getChildFragmetManager()来管理。 var adapter = TabFragmentPagerAdapter ( ...
  • fragment 嵌套

    2018-01-07 15:53:50
    fragment 嵌套fragment 嵌套fragment 嵌套fragment 嵌套fragment 嵌套

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,791
精华内容 7,516
关键字:

fragment嵌套fragment

友情链接: fiepie.zip