[摘]对于Fragment的一些理解

Android  2020年7月14日 pm12:06发布4年前 (2020)更新 城堡大人
88 0 0

Fragment为何要用

Fragment是Android 3.0 (Honeycomb)被引入的。主要目的是为了给大屏幕(如平板电脑)上更加动态和灵活的UI设计提供支持。由于平板电脑的屏幕比手机的屏幕大很多,因此可用于组合和交换的UI组件的空间更大,利用Fragment实现此类设计的时,就无需管理对视图层次结构的复杂更改。

通过将 Activity 布局分成片段,您可以在运行时修改 Activity 的外观,并在由 Activity 管理的返回栈中保留这些更改。如果仅仅只有Activity布局,那是不够的,不仅在手机上有一套布局,同时在平板上还需要设计一套布局,那样维护起来也麻烦,代码上也有一定的冗余,对于APP包的大小也有一定的压力。Fragment的优势是布局在不同设备上的适配。

除此之外,使用Fragment还有这么几个方面优势:

  1. 代码复用。特别适用于模块化的开发,因为一个Fragment可以被多个Activity嵌套,有个共同的业务模块就可以复用了,是模块化UI的良好组件。
  2. Activity用来管理Fragment。Fragment的生命周期是寄托到Activity中,Fragment可以被Attach添加和Detach释放。
  3. 可控性。Fragment可以像普通对象那样自由的创建和控制,传递参数更加容易和方便,也不用处理系统相关的事情,显示方式、替换、不管是整体还是部分,都可以做到相应的更改。
  4. Fragments是view controllers,它们包含可测试的,解耦的业务逻辑块,由于Fragments是构建在views之上的,而views很容易实现动画效果,因此Fragments在屏幕切换时具有更好的控制。

Fragment是什么

说了半天的Fragment,也看到这么多次Fragment这个名词出现,那么Fragment到底是什么东东呢?定义又是如何?

Fragment也可以叫为“片段”,但我觉得“片段”中文叫法有点生硬,还是保持叫Fragment比较好,它可以表示Activity中的行为或用户界面部分。我们可以在一个Activity中用多个Fragment组合来构建多窗格的UI,以及在多个Activity中重复使用某个Fragment。它有自己的生命周期,能接受自己的输入,并且可以在 Activity 运行时添加或删除Fragment(有点像在不同 Activity 中重复使用的“子 Activity”)。

简单来说,Fragment其实可以理解为一个具有自己生命周期的控件,只不过这个控件又有点特殊,它有自己的处理输入事件的能力,有自己的生命周期,又必须依赖于Activity,能互相通信和托管。

Fragment生命周期

Fragment生命周期和Activity生命周期对比图,可以看到两者还是有很多相似的地方,比如都有onCreate(),onStart(),onPause(),onDestroy()等等,因为Fragment是被托管到Activity中的,所以多了两个onAttach()和onDetach()。这里讲讲与Activity生命周期不一样的方法。

onAttach()

Fragment和Activity建立关联的时候调用,被附加到Activity中去。

onCreate()

系统会在创建Fragment时调用此方法。可以初始化一段资源文件等等。

onCreateView()

系统会在Fragment首次绘制其用户界面时调用此方法。 要想为Fragment绘制 UI,从该方法中返回的 View 必须是Fragment布局的根视图。如果Fragment未提供 UI,您可以返回 null。

onViewCreated()

在Fragment被绘制后,调用此方法,可以初始化控件资源。

onActivityCreated()

当onCreate(),onCreateView(),onViewCreated()方法执行完后调用,也就是Activity被渲染绘制出来后。

onPause()

系统将此方法作为用户离开Fragment的第一个信号(但并不总是意味着此Fragment会被销毁)进行调用。 通常可以在此方法内确认在当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。

onDestroyView()

Fragment中的布局被移除时调用。

onDetach()

Fragment和Activity解除关联的时候调用。

但需要注一点是:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现。

Fragment怎么用

前面介绍了半天,不耐烦的人会说,这么多废话,也不见的到底是如何使用,毕竟我们是开发者,需要的使用方式,那么现在就来说说用法如何吧。两种方式:静态用法和动态用法。

静态用法

1、继承Fragment,重写onCreateView决定Fragemnt的布局

2、在Activity中声明此Fragment,就当和普通的View一样

首先是布局文件:fragment1.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ff00" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is fragment 1"
        android:textColor="#000000"
        android:textSize="25sp" />

</LinearLayout>

可以看到,这个布局文件非常简单,只有一个LinearLayout,里面加入了一个TextView。我们再新建一个fragment2.xml,代码跟上面一样,只是改不了背景颜色。

然后新建一个类Fragment1,这个类是继承自Fragment的:

 public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment1, container, false);
    }
}

可以看到,在onCreateView()方法中加载了fragment1.xml的布局。同样fragment2.xml也是一样的做法。

然后打开或新建activity_main.xml作为主Activity的布局文件,在里面加入两个Fragment的引用,使用android:name前缀来引用具体的Fragment:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false" >

    <fragment
        android:id="@+id/fragment1"
        android:name="com.example.fragmentdemo.Fragment1"
        android:layout_width="0dip"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/fragment2"
        android:name="com.example.fragmentdemo.Fragment2"
        android:layout_width="0dip"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

最后新建MainActivity作为程序的主Activity,里面的代码非常简单,都是自动生成的。

现在我们来运行一次程序,就会看到,一个Activity很融洽地包含了两个Fragment,这两个Fragment平分了整个屏幕。

动态用法

上面仅仅是Fragment简单用法,它真正强大部分是在动态地添加到Activity中,那么动态用法又是如何呢?

还是在静态用法代码的基础上修改,打开activity_main.xml,将其中对Fragment的引用都删除,只保留最外层的LinearLayout,并给它添加一个id,因为我们要动态添加Fragment,不用在XML里添加了,删除后代码如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false" >

</LinearLayout>

然后打开MainActivity,修改其中的代码如下所示:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Display display = getWindowManager().getDefaultDisplay();
        if (display.getWidth() > display.getHeight()) {
            Fragment1 fragment1 = new Fragment1();
            getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit();
        } else {
            Fragment2 fragment2 = new Fragment2();
            getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment2).commit();
        }
    }

}

看到了没,首先,我们要获取屏幕的宽度和高度,然后进行判断,如果屏幕宽度大于高度就添加fragment1,如果高度大于宽度就添加fragment2。

动态添加Fragment主要分为4步:

  1. 获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。
  2. 开启一个事务,通过调用beginTransaction方法开启。
  3. 向容器内加入Fragment,一般使用replace方法实现,需要传入容器的id和Fragment的实例。
  4. 提交事务,调用commit方法提交。

要想管理 Activity 中的片段,需要使用 FragmentManager。要想获取它,需要 Activity 调用 getFragmentManager()。

使用 FragmentManager 执行的操作包括:

通过 findFragmentById()(对于在 Activity 布局中提供 UI 的片段)或 findFragmentByTag()(对于提供或不提供 UI 的片段)获取 Activity 中存在的片段 通过 popBackStack()将片段从返回栈中弹出 通过 addOnBackStackChangedListener() 注册一个侦听返回栈变化的侦听器 也可以使用 FragmentManager 打开一个 FragmentTransaction,通过它来执行某些事务,如添加和删除片段。

Fragment通信

尽管 Fragment 是作为独立于 Activity的对象实现,并且可在多个 Activity 内使用,但Fragment 的给定实例会直接绑定到包含它的 Activity。具体地说,Fragment 可以通过 getActivity() 访问 Activity实例,并轻松地执行在 Activity 布局中查找视图等任务。如:

View listView = getActivity().findViewById(R.id.list);

同样地,Activity 也可以使用 findFragmentById() 或 findFragmentByTag(),通过从 FragmentManager 获取对 Fragment 的引用来调用Fragment中的方法。例如:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
创建对 Activity 的事件回调

在某些情况下,可能需要通过与 Activity 共享事件。执行此操作的一个好方法是,在Fragment 内定义一个回调接口,并要求宿主 Activity 实现它。 当 Activity 通过该接口收到回调时,可以根据需要与布局中的其他Fragment共享这些信息。

摘抄

抱歉,忘记部分摘抄于哪了。

 历史上的今天

  1. 2021: 食指:相信未来(0条评论)
  2. 2019: 丰子恺:秋(1条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

Java反射记录

前言反射机制是运行程序运行过程中操作(访问和修改)类的各种属性以及方法。正文作用判断任意一个对象所属的类构造任意一个类的对象判断任意一个类所具有的成员变量和方法(包括private)调用任意一个对象的方法缺点不断地生成变量,不断的GC,影响性能参考文章

丰子恺:秋

我的年岁上冠用了“三十”二字,至今已两年了。不解达观的我,从这两个字上受到了不少的暗示与影响。虽然明明觉得自己的体格与精力比二十九岁时全然没有什么差异,但“三十”这一个观念笼在头上,犹之张了一顶阳伞,使我的全身蒙了一个暗淡色的阴影,又仿佛在日历上撕过了立秋的一页以后,虽然太阳的炎威依然没有减却,寒暑...

JNI学习手册

前言之前初略的学习了一下JNI的使用,也做了对应的笔记。为了方便自己复现,这里就把所有文章整理在一起,方便自己查询。正文JNI之数据类型Java中调到Native方法传递的参数是Java类型,这些参数需要通过Dalvik虚拟机转换为JNI类型。具体请看《JNI之类型介绍》基本数据类型...

里柯克:吃饼冠军乔.布朗

我们当中的一位伟大人物。吃饼冠军乔.布朗给人的第一个印象是不嚣张,没架子,身材并不怎么出众,举止坦率随便,一点儿也不让人感到拘束。“请坐吧,”他朝凉台上的摇椅挥挥手,对我们说(我们是一些从报社来采访的记者)。“就坐下吧。天儿挺热的,对不?”他话说得那么朴实,口气又那么和蔼可亲,我们马上就不再感...

林语堂:人生的乐趣

我们只有知道一个国家人民生活的乐趣,才会真正了解这个国家,正如我们只有知道一个人怎样利用闲暇时光,才会真正了解这个人一样。只有当一个人歇下他手头不得不干的事情,开始做他所喜欢做的事情时,他的个性才会显露出来。只有当社会与公务的压力消失,金钱、名誉和野心的刺激离去,精神可以随心所欲地游荡之时,我们才会...

付志勇:我的秋天没有忧伤

我喜欢秋天胜过任何一个季节,我喜欢那弹指可破的空气、橙色明亮的阳光甚至草枯、花落、风吹过大地 我喜欢在秋天里写诗写我三十年一晃而过的光阴写我尘世里的清欢写窗外飘落的叶子渐渐覆盖住旧事 秋天让我回望过去但更多的思索将来一场繁华的凋敝是不是意味着另一场繁华...