Android开发 —Fragment片段布局

前言

Fragment想必我们不生疏吧,在一般成本中,对于Fragment的使用也很频仍,现在主流的APP中,基本的架构也都是一个主页,然后每个Tab项用Fragment做布局,分化选项做切换,使用起来也有利于。不过否对它有丰富的认识吗,谷歌(谷歌)推举用Fragment来代替Activity,但又没有明确说为啥要用Fragment来代表Activity,那里就吸引争议了,那究竟是要不要用,是否利用Fragment完全替换Activity真的比常规开发形式更好吧?假若要用的话,那需求通晓怎么要利用Fragment,Fragment是什么样,它的生命周期如何,咋样利用,通信又是怎么样,有啥毛病吗?带着这个题目,我们逐条去解读。

目录

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

Fragment为啥要用

Fragment是Android 3.0
(Honeycomb)被引入的。紧要目标是为了给大屏幕(如surface)上更加动态和灵活的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
内使用,但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也有局地注意事项,不是那么完美的,就算谷歌(Google)引进我们用Fragment来顶替Activity来利用,大家也真的那做了,现在中央主流的APP也都是少量Activity+浩大Fragment,但也须求防止有些坑慎入

 

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

相关文章