前言

Fragment想必我们不陌生吧,在通常支付中,对于Fragment的运用也很频繁,现在主流的APP中,基本的架构也都是一个主页,然后每个Tab项用Fragment做布局,不同采纳做切换,使用起来也造福。可是否对它有丰盛的认识吗,Google引荐用Fragment来代表Activity,但又不曾确定性说为啥要用Fragment来替代Activity,这里就吸引争议了,这究竟是要不要用,是否利用Fragment完全替换Activity真的比常规开发情势更好呢?倘诺要用的话,这需要领悟怎么要利用Fragment,Fragment是怎么,它的生命周期如何,如何运用,通信又是怎样,有什么毛病吗?带着那一个题材,我们各种去解读。

目录

  • Fragment为啥要用
  • Fragment是什么
  • Fragment生命周期
  • Fragment怎么用
  • Fragment通信
  • Fragment是否很周密
  • 小结
  • 参考地址

Fragment为什么要用

Fragment是Android 3.0
(Honeycomb)被引入的。首要目标是为了给大屏幕(如三星GALAXY Tab)上更为动态和灵活的UI设计提供扶助。由于机械电脑的屏幕比手机的屏幕大过多,因而可用于组合和交流的UI组件的半空中更大,利用Fragment实现此类设计的时,就无需治本对视图层次结构的纷繁更改。

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

比如:

图片 1

从图中我们可以见到,在机械中,一个Activity
A包含了三个Fragment,分别是Fragment A和Fragment
B,但在手机中吗,就需要五个Activity,分别是Activity A包含Fragment
A和Activity B包含Fragment
B。同时每个Fragment都抱有温馨的一套生命周期回调方法,并各自处理自己的用户输入事件。
因而,在平板中行使一个Activity 就足以了,右边是列表,右侧是内容详情。

除此之外,使用Fragment还有这样多少个位置优势:

  • 代码复用。特别适用于模块化的支付,因为一个Fragment可以被多少个Activity嵌套,有个协同的事务模块就可以复用了,是模块化UI的脍炙人口组件。
  • Activity用来治本Fragment。Fragment的生命周期是寄托到Activity中,Fragment可以被Attach添加和Detach释放。
  • 可控性。Fragment可以像一般对象这样自由的创始和操纵,传递参数更加容易和造福,也不用处理系列有关的工作,突显模式、替换、不管是完全依旧有些,都可以做到相应的变动。
  • 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生命周期

如图:

图片 2

这张图是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的时候,它的生命周期就会实施这一个情势。

图片 3

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

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

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

</LinearLayout>  

接下来新建一个类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也是一律的做法,新建一个Fragment2类:

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

下一场打开或新建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,里面的代码非常简单,都是自动生成的:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
    }  
}  

近期我们来运行四遍程序,就会看到,一个Activity很要好地包含了多少个Fragment,这多少个Fragment平分了百分之百屏幕,效果图如下:
图片 4

动态用法

上边仅仅是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方法提交。

现行运作一下主次,效果如下图所示:

图片 5

图片 6

要想治本 Activity 中的片段,需要采用 FragmentManager。要想取得它,需要
Activity 调用 getFragmentManager()。

行使 FragmentManager 执行的操作包括:

  • 通过 findFragmentById()(对于在 Activity 布局中提供 UI
    的有些)或 findFragmentByTag()(对于提供或不提供 UI 的有的)获取
    Activity 中留存的局部
  • 经过 popBackStack()将有些从再次来到栈中弹出
  • 因而 addOnBackStackChangedListener() 注册一个侦听重回栈变化的侦听器

也足以利用 FragmentManager 打开一个 FragmentTransaction,通过它来推行某些事情,如添加和删除片段。

Fragment通信

即便 Fragment 是用作独立于 Activity的对象实现,并且可在六个 Activity
内利(内尔(Nell)y)用,但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共享那些消息。

例如,即便一个信息应用的 Activity 有七个Fragment
,一个用来呈现作品列表(Fragment A),另一个用以显示随笔(Fragment
B)—,那么Fragment A必须在列表项被选定后告知
Activity,以便它报告Fragment B 展现该小说。
在本例中,OnArticleSelectedListener 接口在部分 A 内注明:

public static class FragmentA extends ListFragment { 
    public interface OnArticleSelectedListener { 
        public void onArticleSelected(Uri articleUri);
    } 
} 

然后,该Fragment的宿主 Activity
会实现 OnArticleSelectedListener 接口并代表 onArticleSelected(),将来自Fragment
A 的风波通报Fragment B。为确保宿主 Activity 实现此界面,Fragment A
的 onAttach() 回调方法(系统在向 Activity
添加Fragment时调用的点子)会通过更换传递到 onAttach() 中的 Activity 来实例化 OnArticleSelectedListener 的实例:

public static class FragmentA extends ListFragment { 
    OnArticleSelectedListener mListener;
    @Override 
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try { 
            mListener = (OnArticleSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
        } 
    } 
} 

假定 Activity
未落实界面,则有的会引发 ClassCastException。实现时,mListener 成员会保留对
Activity 的 OnArticleSelectedListener 实现的引用,以便Fragment A
可以经过调用 OnArticleSelectedListener 界面定义的点子与 Activity
共享事件。例如,假若Fragment A
是 ListFragment 的一个扩大,则用户每一趟点击列表项时,系统都会调用Fragment中的 onListItemClick(),然后该方法会调用 onArticleSelected() 以与
Activity 共享事件:

public static class FragmentA extends ListFragment {
    OnArticleSelectedListener mListener;
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);
        mListener.onArticleSelected(noteUri);
    }
}

Fragment是否很周密

因为Fragment是由FragmentManager来保管,每一个Activity有一个FragmentManager,管理着一个Fragment的栈,Activity是系统级此外,由系统来管理ActivityManager,栈也是系统范围的。而Fragment则是各种Activity范围内的,所以在行使Fragment的时候也有几点要留意。

  • 同一个Activity中,只可以有一个ID或TAG标识的Fragment实例。
    这很容易掌握,同一个限制内,有标识的实例肯定是要唯一才行(否则还要标识干嘛)这么些在布局中日常犯错,在布局中写Fragment最好永不加ID或者TAG,否则很容易出现不同意创造的谬误。我的规则是一旦放在布局中,就绝不加ID和TAG,假若急需ID和TAG就全用代码控制。创立新实例前先到FragmentManager中搜寻一番,这也正是有标识的含义所在。
  • 一个Activity中有一个Fragment池,实例不肯定会被灭绝,可能会保留在池中。
    其一跟第一点差不多。就好比系统会缓存Activity的实例一样,FragmentManager也会缓存Fragment实例,以方便和增速再一次展示。
  • FragmentManager的效率范围是全体Activity,所以,某一个搭架子ID,不可能再度被Fragment替换。
    一般呈现Fragment有三种情势,一种是层叠到某个布局上,或者把某部布局方面的Fragment替换掉,可是这多少个布局无法出现二次,比如布局A中有ID为id的区域,要显得为Fragment,此布局A,只可以在一个Activity中显得一个,否则第二个id区域无法被Fragment成功替换。因为虽有二个ID布局的实例,但ID是同等的,对FragmentManager来说是平等的,它会以为唯有一个,因为它看的是布局的ID,而不是布局的实例。
  • Fragment的生命周期反应Activity的生命周期。
    Fragment在显示和剥离时会走五回完整的生命周期。此外,正在呈现时,就跟Activity的等同,Activity被onPause,里面的Fragment就onPause,以此类推,由此拉动的题材尽管,比如您在onStart()里面做了部分事情,那么,当宿主Activity被挡住,又出现时(比如接了个电话),Fragment的onStart也会被高到,所以你要想开,这么些生命周期不单单在展现和剥离时会走到。
  • Fragment的可见性。
    其一题材出现在有Fragment栈的时候,也就是说每个Fragment不知情自己是不是真的对用户可见。比如现在是Fragment
    A,又在其下边显示了Fragment
    B,当B显示后,A并不知道自己下边还有一个,也不知晓自己对用户不可见了,同样再有一个C,B也不知。C退出后,B依然不知自己已在栈顶,对用户可见,B退后,A也不知。也就是说Fragment展现或者退出,栈里的别样Fragment不可以感知。那点就不如Activity,a被b盖住后,a会走到onStop(),同样c突显后,b也能透过onStop()感知。Fragment能够从FragmentManager监听BackStackState的变迁,但它只报告您Stack变了,不报告你是多了,依旧少,还有你处的地点。有一个解决方案就是,记录页面的Path深度,再跟Fragment所在的Stack深度来相比较,假使一致,那么这些Fragment就在栈顶。因为各类页面的Path深度是原则性的,而Stack深度是不转移的,所以这么些能确切的判断Fragment是否对用户可见,当然,那一个仅针对所有页面有效,对于布局中的一个区域是无效的。
  • Fragment的轩然大波传递。
    对此层叠的Fragment,其实就一定于在一个FrameLayout里面添加一堆的View,所以,假如处在顶层的Fragment没处理点击事件,那么事件就会向下层传递,直到事件被处理。比如有二个Fragment
    A和B,B在A上边,B唯有TextView且没处理事件,那么点击B时,会发觉A里的View处理了事件。这么些对于Activity也不会发生,因为事件无法跨窗体传播,上边的Activity没处理事件,也不会传给下边的Activity,尽管它可见。解决之法,就是让地点的Fragment的根布局吃掉事件,为各种根ViewGroup添加onClick=“true”。
  • 与第三方Activity交互。与第三方相互,仍要选取Android的正规startActivityForResult()和onActivityResult()这二个主意来开展。但对于Fragment有些事情需要专注,Fragment也有这二个措施,不过为了能科学的让Fragment收到onActivityResult(),需要:
  1. 宿主Activity要落实一个空的onActivityResult(),里面调用super.onActivityResult()
  2. 调用Fragment#startActivityForResult()而不是用Activity的
    当然,也足以直接采取Activity的startActivityForResult(),这样的话,就只可以在宿主Activity里处理回来的结果了。

小结

在用法的代码部分参考郭神的博客,感觉郭神在代码讲解部分通俗易懂,看起来也有利。综上说述,在应用Fragment也有局部注意事项,不是那么完美的,尽管谷歌援引我们用Fragment来顶替Activity来拔取,我们也确确实实这做了,现在为主主流的APP也都是少量Activity+广大Fragment,但也需要防止有些坑慎入

 

正文摘自:https://www.cnblogs.com/cr330326/p/5712022.html

相关文章

网站地图xml地图