在Android 中Fragment 中嵌套使用Fragment 中使用

1. 前言

       这几天接到一个坑的任务,领导要我做一个Android 蓝牙APK,要求是在平板上使用并且横屏分页显示,一边显示蓝牙广播搜索的设备,另一边存放指定已过滤的设备。

       在Android中横屏显示,并且分页,自然而然就想到了Fragment,于是抽空学习一下Fragment的用法,并且在使用过程中遇到findFragmentById 返回为null。

今天遇到这个问题,真是头疼死了,找了很多资料都说是这样子使用,在原本可以运行的项目中的findFragmentByid返回值为null,原本可以运行的项目,竟然运行报错。

因此才有这一篇文章。

2. 基本概念

      Fragment,又称碎片,也可以说是Activity的一个片段,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6。

  • Fragment是依赖于Activity的,不能独立存在的。
  • 一个Activity里可以有多个Fragment。
  • 一个Fragment可以被多个Activity重用。
  • Fragment有自己的生命周期,并能接收输入事件。
  • 我们能在Activity运行时动态地添加或删除Fragment。

Fragment的优势有以下几点:

  • 模块化(Modularity):我们不必把所有代码全部写在Activity中,而是把代码写在各自的Fragment中。
  • 可重用(Reusability):多个Activity可以重用一个Fragment。
  • 可适配(Adaptability):根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这样用户体验更好。

3. Fragment生命周期(参考菜鸟教程《Fragment基本概述》

4. Fragment 使用(参考菜鸟教程《Fragment基本概述》

Fragment 使用有两种方式,分为静态加载Fragment 动态加载Fragment

4.1 静态加载Fragment

对于静态加载需要注意的是:

4.1.1. 通过xml的方式添加,缺点是一旦添加就不能在运行时删除

4.1.2 自定义一个Fragment类,需要继承Fragment或者他的子类,重写onCreateView()方法 在该方法中调用:Inflater.inflate()方法加载Fragment的布局XML文件,接着返回加载的view对象,在Inflater.inflat方法中的第三个参数必须为false,因为它还要停靠在容器中。

第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常:

Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call 

4.1.3 在需要加载Fragment的Activity或者父Fragment(Fragment 包含Fragment) 对应的布局文件中添加fragment的标签, 记住,name属性是全限定类名哦,就是要包含Fragment的包名,如下:

<FrameLayout
        android:id="@+id/layout_container"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="4">

        <fragment
            android:id="@+id/home_left_fragment"
            android:name="com.radio.ble.ui.fragment.impl.LeftFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>

    <View
        android:layout_width="0.1dp"
        android:layout_height="match_parent"
        android:background="#D1CFCF" />

    <FrameLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3">

        <fragment
            android:id="@+id/home_right_fragment"
            android:name="com.radio.ble.ui.fragment.impl.RightFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
public abstract class BaseFragment extends Fragment
{
    protected View mRootView;

    protected Activity mActivity;

    @Override
    public void onCreate(Bundle saveInstanceState)
    {
        super.onCreate(saveInstanceState);
        mActivity = getActivity();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return initView();
    };

    //当fragment 依赖的activity onCreate方法结束时使用
    @Override
    public void onActivityCreated(Bundle saveInstanceState)
    {
        super.onActivityCreated(saveInstanceState);
        initData();
    }

    //子类必须初始化
    public abstract View initView();

    //子类初始化数据
    public abstract void initData();
}

4.2 动态加载Fragment(参考菜鸟教程《Fragment基本概述》

4.2.1 在动态添加方式中,首先需要Activity 或者 父Fragment 中有一个

一个容器存放Fragment,一般是FrameLayout,因此在Activity的布局文件中加入FrameLayout:

<FrameLayout
    android:id="@+id/frame_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

在onCreate()中,通过以下代码将Fragment添加进Activity中

if (bundle == null) {
    getSupportFragmentManager().beginTransaction()
        .add(R.id.container, Fragment1.newInstance("hello world"), "f1")
        .commit();
}

使用动态方式,add()方法的第三个参数是fragment的tag名,指定tag的好处是后续我们可以通过Fragment1 frag = getSupportFragmentManager().findFragmentByTag("f1")从FragmentManager中查找Fragment对象。

5. Fragment与Activity的交互(参考菜鸟教程《Fragment基本概述》

5.1Fragment向Activity传递数据

在Fragment中定义接口,并让Activity实现该接口。

5.2 Activity向Fragment传递数据

Activity向Fragment传递数据比较简单,获取Fragment对象,并调用Fragment的方法即可,比如要将一个字符串传递给Fragmen

5.3Fragment之间通信

由于Fragment之间是没有任何依赖关系的,因此如果要进行Fragment之间的通信,建议通过Activity作为中介,不要Fragment之间直接通信,如下:

6. 在Fragment 中获取控件的方法,

mRootView = UIUtils.inflate(R.layout.fragment_home_left_layout);

        mRefreshLayout = (SwipeRefreshLayout) mRootView.findViewById(R.id.refreshLayout);
        mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
        {
            @Override
            public void onRefresh() {
                scanLeDevice(true);
            }
        });

        listView = (MyListView) mRootView.findViewById(R.id.listView1);

7. Activity中获取Fragment组件的方法

首先getFragmentManager 、getSupportFragmentManager这个两个FragmentManager用的最多,Fragment是安卓3.0以后引入的API,FragmentManager是管理Fragment的片段管理器,直接使用,再

Fragment获得Activity中的组件: getActivity().findViewById(R.id.list);
Activity获得Fragment中的组件(根据id和tag都可以):getFragmentManager.findFragmentByid(R.id.fragment1);

8. Fragment 嵌套使用时,获取组件方法

当Fragment嵌套Fragment时(也就是说你的Fragment里面还有子Fragment),里面需要用getChildFragmentManager来获得FragmentManager,再使用findViewById(R.id.list), 或者findFragmentByid(R.id.fragment1);

关于Fragment 一些基本的认识就这些了,学习还要继续,付出总有回报的。

参考:

《Android Fragment 非常详细的一篇》

Fragment嵌套Fragment中getChildFragmentManager的问题

对于Fragment的一些理解

猜你喜欢

转载自blog.csdn.net/gd6321374/article/details/100661149