Fragment详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fragment详解相关的知识,希望对你有一定的参考价值。

参考技术A

Activity用来管理Fragment。因为一个Fragment可以被多个Activity嵌套,有个共同的业务模块就可以复用了

Fragment具有自己生命周期,是模块化UI的良好组件。

Fragment的生命周期是寄托到Activity中,Fragment可以被Attach添加和Detach释放。

Fragments是view controllers,它们包含可测试的,解耦的业务逻辑块,由于Fragments是构建在views之上的,而views很容易实现动画效果,因此Fragments在屏幕切换时具有更好的控制。

Fragment可以像普通对象那样自由的创建和控制,传递参数更加容易和方便,也不用处理系统相关的事情,显示方式、替换、不管是整体还是部分,都可以做到相应的更改。

可以看出Fragment生命周期与Activity类似

解释如下:

上面的方法中,只有onCreateView()在重写时不用写super方法,其他都需要。

因为Fragment依赖Activity,那么Fragment和Activity的生命周期可谓是息息相关,如下图所示

Activity的FragmentManager负责调用队列中Fragment的生命周期方法,只要Fragment的状态与Activity的状态保持了同步,托管Activity的FragmentManager便会继续调用其他生命周期方法以继续保持Fragment与Activity的状态一致。

Activity-onCreate(begin) ,Fragment-onAttach-onCreate-onCreateView-onViewCreated, Activity-onCreate(end) ,Fragment-onActivityCreated, Activity-onStart ,Fragment-onStart, Activity-onResume ,Fragment-onResume

Fragment-onPause, Activity-onPause ,Fragment-onStop, Activity-onStop

Activity-onRestart-onStart ,Fragment-onStart, Activity-onResume ,Fragment-onResume

Fragment-onPause, Activity-onPause ,Fragment-onStop, Activity-onStop ,Fragment-onDestroyView-onDestroy-onDetach, Activity-onDestroy

Fragment的管理则交由FragmentActivity的FragmentManager来实现。

获取方式:

注意 :在fragment创建childFragment的时候,需要注意的是:使用getChildFragmentManager() 使用getFragmentManager()会导致内存泄漏

常用API:

popBackStackImmediate相关的方法与上面逻辑是一样的与上面不同的是,在调用的时候会立即执行弹出。

通过FragmentTransaction实现在Activity运行时可动态地加入、移除、交换Fragment

FragmentTransaction的主要方法介绍

针对在一个Activity中的某个Layout中切换Fragment,无非两种方法:

当移除或替换一个片段并向返回栈添加事务时,系统会停止(而非销毁)移除的片段。 如果用户执行回退操作进行片段恢复,该片段将重新启动。

具体实例可参看: Fragment的addToBackStack()使用

commit(), commitNow()和commitAllowingStateLoss()区别分析

实例:

使用setArguments(Bundle args)传递,在onCreate中使用getArguments()取出。和Activity的Intent恢复机制类似。

1、如果你需要在Fragment中用到宿主Activity对象,建议在你的基类Fragment定义一个Activity的全局变量,在onAttach中初始化,这不是最好的解决办法,但这可以有效避免一些意外Crash。

2、onHiddenChanged的回调时机

当使用add()+show(),hide()跳转新的Fragment时,旧的Fragment回调onHiddenChanged(),不会回调生命周期方法,而新的Fragment在创建时是不会回调onHiddenChanged()

推荐阅读: Fragment全解析系列(二):正确的使用姿势 、 Fragment全解析系列(一):那些年踩过的坑

Fragment生命周期详解

Fragment依附Activity而存在,本文通过两个TextView切换两个Fragment来观察Activity和两个Fragment在不同操作下各执行哪些方法,从而对其生命周期有更加深刻的了解。通过打印log进行分析。

  • 本文要点:
  1. Fragment的动态加载,和切换。
  2. Fragment和Activity的生命周期分析。
  • 注:文中:
  1. 使用ButterKnife,免去findViewById。
  2. LogUtils.e()为个人工具类,可等视为log.e()
  • 进入LifeActivity时,Fragment1显示:
  1. 先执行LifeActivity onCreate方法,再执行Fragment1onAttachonAttach、onCreateView、onActivityCreated方法。
  2. LifeActivity、Fragment1 onStart方法 到 LifeActivity、Fragment1 onResume方法 可见在初始化时Activity要优先Fragment一步。

 

03-29 23:09:43.827 14564-14564/top.toly.www.fragment E/LifeActivity: onCreate: ====LifeActivity
03-29 23:09:43.831 14564-14564/top.toly.www.fragment E/Fragment1: onAttach: ====Fragment1
03-29 23:09:43.831 14564-14564/top.toly.www.fragment E/Fragment1: onCreate: ====Fragment1
03-29 23:09:43.831 14564-14564/top.toly.www.fragment E/Fragment1: onCreateView:====Fragment1 
03-29 23:09:43.832 14564-14564/top.toly.www.fragment E/Fragment1: onActivityCreated:====Fragment1 
03-29 23:09:43.832 14564-14564/top.toly.www.fragment E/LifeActivity: onStart: ====LifeActivity
03-29 23:09:43.832 14564-14564/top.toly.www.fragment E/Fragment1: onStart: ====Fragment1
03-29 23:09:43.832 14564-14564/top.toly.www.fragment E/LifeActivity: onResume: ====LifeActivity
03-29 23:09:43.832 14564-14564/top.toly.www.fragment E/Fragment1: onResume:====Fragment1 

  • 将屏幕关闭时:Fragment1LifeActivity分别执行onPauseonStop方法。 可见在暂停时Fragment要优先Activity一步。
03-29 23:17:12.928 19745-19745/top.toly.www.fragment E/Fragment1: onPause:====Fragment1
03-29 23:17:12.928 19745-19745/top.toly.www.fragment E/LifeActivity: onPause: ====LifeActivity
03-29 23:17:12.960 19745-19745/top.toly.www.fragment E/Fragment1: onStop: ====Fragment1
03-29 23:17:12.960 19745-19745/top.toly.www.fragment E/LifeActivity: onStop: ====LifeActivity

  • 将屏幕打开时:LifeActivityonRestartLifeActivityFragment1onStart。LifeActivityFragment1onResume
03-29 23:17:59.144 19745-19745/top.toly.www.fragment E/LifeActivity: onRestart: ====LifeActivity
03-29 23:17:59.153 19745-19745/top.toly.www.fragment E/LifeActivity: onStart: ====LifeActivity
03-29 23:17:59.153 19745-19745/top.toly.www.fragment E/Fragment1: onStart: ====Fragment1
03-29 23:17:59.154 19745-19745/top.toly.www.fragment E/LifeActivity: onResume: ====LifeActivity
03-29 23:17:59.154 19745-19745/top.toly.www.fragment E/Fragment1: onResume:====Fragment1

  • Fragment1切到Fragment2时:
03-29 23:20:49.003 22825-22825/top.toly.www.fragment E/Fragment1: onPause:====Fragment1 
03-29 23:20:49.005 22825-22825/top.toly.www.fragment E/Fragment1: onStop: ====Fragment1
03-29 23:20:49.005 22825-22825/top.toly.www.fragment E/Fragment1: onDestroyView: ====Fragment1
03-29 23:20:49.005 22825-22825/top.toly.www.fragment E/Fragment1: onDestroy:====Fragment1 
03-29 23:20:49.006 22825-22825/top.toly.www.fragment E/Fragment1: onDetach:====Fragment1 
03-29 23:20:49.006 22825-22825/top.toly.www.fragment E/Fragment2: onAttach: ====Fragment2
03-29 23:20:49.006 22825-22825/top.toly.www.fragment E/Fragment2: onCreate: ====Fragment2
03-29 23:20:49.006 22825-22825/top.toly.www.fragment E/Fragment2: onCreateView:====Fragment2 
03-29 23:20:49.035 22825-22825/top.toly.www.fragment E/Fragment2: onActivityCreated:====Fragment2 
03-29 23:20:49.035 22825-22825/top.toly.www.fragment E/Fragment2: onStart: ====Fragment2
03-29 23:20:49.035 22825-22825/top.toly.www.fragment E/Fragment2: onResume:====Fragment2 

  • Fragment2切到Fragment1时:

 

03-29 23:22:18.835 22825-22825/top.toly.www.fragment E/Fragment2: onPause:====Fragment2 
03-29 23:22:18.835 22825-22825/top.toly.www.fragment E/Fragment2: onStop: ====Fragment2
03-29 23:22:18.835 22825-22825/top.toly.www.fragment E/Fragment2: onDestroyView: ====Fragment2
03-29 23:22:18.836 22825-22825/top.toly.www.fragment E/Fragment2: onDestroy:====Fragment2 
03-29 23:22:18.836 22825-22825/top.toly.www.fragment E/Fragment2: onDetach:====Fragment2 
03-29 23:22:18.837 22825-22825/top.toly.www.fragment E/Fragment1: onAttach: ====Fragment1
03-29 23:22:18.837 22825-22825/top.toly.www.fragment E/Fragment1: onCreate: ====Fragment1
03-29 23:22:18.837 22825-22825/top.toly.www.fragment E/Fragment1: onCreateView:====Fragment1 
03-29 23:22:18.840 22825-22825/top.toly.www.fragment E/Fragment1: onActivityCreated:====Fragment1 
03-29 23:22:18.840 22825-22825/top.toly.www.fragment E/Fragment1: onStart: ====Fragment1
03-29 23:22:18.840 22825-22825/top.toly.www.fragment E/Fragment1: onResume:====Fragment1 

 


  • 退出LifeActivity时:
03-29 23:11:47.792 14564-14564/top.toly.www.fragment E/Fragment1: onPause:====Fragment1 
03-29 23:11:47.792 14564-14564/top.toly.www.fragment E/LifeActivity: onPause: ====LifeActivity
03-29 23:11:47.798 14564-14564/top.toly.www.fragment E/Fragment1: onStop: ====Fragment1
03-29 23:11:47.798 14564-14564/top.toly.www.fragment E/LifeActivity: onStop: ====LifeActivity
03-29 23:11:47.798 14564-14564/top.toly.www.fragment E/Fragment1: onDestroyView: ====Fragment1
03-29 23:11:47.799 14564-14564/top.toly.www.fragment E/Fragment1: onDestroy:====Fragment1 
03-29 23:11:47.799 14564-14564/top.toly.www.fragment E/Fragment1: onDetach:====Fragment1 
03-29 23:11:47.799 14564-14564/top.toly.www.fragment E/LifeActivity: onDestroy: ====LifeActivity
  • 下面是具体代码。(源码地址:https://github.com/toly1994328/Fragment.git)

 

 

 

LifeActivity.java

 

 1 package top.toly.www.fragment.life;
 2 
 3 import android.app.FragmentManager;
 4 import android.app.FragmentTransaction;
 5 import android.os.Bundle;
 6 import android.support.v7.app.AppCompatActivity;
 7 import android.view.View;
 8 import android.widget.FrameLayout;
 9 import android.widget.TextView;
10 
11 import butterknife.Bind;
12 import butterknife.ButterKnife;
13 import butterknife.OnClick;
14 import top.toly.www.fragment.R;
15 import utils.shortUtils.LogUtils;
16 
17 public class LifeActivity extends AppCompatActivity {
18     private static final String TAG = "LifeActivity";
19 
20     @Bind(R.id.tv_title1)
21     TextView mTvTitle1;
22     @Bind(R.id.tv_title2)
23     TextView mTvTitle2;
24     @Bind(R.id.fl_life_root)
25     FrameLayout mFlLifeRoot;
26     private FragmentManager mFm;
27     private FragmentTransaction mFt;
28 
29     @Override
30     protected void onCreate(Bundle savedInstanceState) {
31         super.onCreate(savedInstanceState);
32         setContentView(R.layout.activity_life);
33         LogUtils.e(TAG, "onCreate: ====LifeActivity");
34         ButterKnife.bind(this);
35         initFragment();//初始Fragment
36     }
37 
38     @Override
39     protected void onStart() {
40         super.onStart();
41         LogUtils.e(TAG, "onStart: ====LifeActivity");
42     }
43 
44     @Override
45     protected void onResume() {
46         super.onResume();
47         LogUtils.e(TAG, "onResume: ====LifeActivity");
48     }
49 
50     @Override
51     protected void onPause() {
52         super.onPause();
53         LogUtils.e(TAG, "onPause: ====LifeActivity");
54     }
55 
56     @Override
57     protected void onStop() {
58         super.onStop();
59         LogUtils.e(TAG, "onStop: ====LifeActivity");
60     }
61 
62     @Override
63     protected void onRestart() {
64         super.onRestart();
65         LogUtils.e(TAG, "onRestart: ====LifeActivity");
66     }
67     @Override
68     protected void onDestroy() {
69         super.onDestroy();
70         LogUtils.e(TAG, "onDestroy: ====LifeActivity");
71     }
72 
73     private void initFragment() {
74         mFm = getFragmentManager();//1.获取FragmentManager
75         mFt = mFm.beginTransaction();//2.fm开启事务
76         mFt.add(R.id.fl_life_root, new Fragment1()); //3.动态添加
77         mFt.commit();//4.提交事务
78     }
79 
80     @OnClick({R.id.tv_title1, R.id.tv_title2})
81     public void onViewClicked(View view) {
82         mFt = mFm.beginTransaction();//2.fm开启事务
83         switch (view.getId()) {
84             case R.id.tv_title1:
85                 mFlLifeRoot.removeAllViews();//先清屏
86                 mFt.replace(R.id.fl_life_root, new Fragment1()); //3.动态添加
87                 break;
88             case R.id.tv_title2:
89                 mFlLifeRoot.removeAllViews();//先清屏
90                 mFt.replace(R.id.fl_life_root, new Fragment2()); //3.动态添加
91                 break;
92         }
93         mFt.commit();//4.提交事务
94     }
95 }

Fragment1.java

 1 package top.toly.www.fragment.life;
 2 
 3 
 4 import android.app.Fragment;
 5 import android.content.Context;
 6 import android.os.Bundle;
 7 import android.view.LayoutInflater;
 8 import android.view.View;
 9 import android.view.ViewGroup;
10 
11 import top.toly.www.fragment.R;
12 import utils.shortUtils.LogUtils;
13 
14 /**
15  * A simple {@link Fragment} subclass.
16  */
17 public class Fragment1 extends Fragment {
18     private static final String TAG = "Fragment1";
19 
20     public Fragment1() {
21         // Required empty public constructor
22     }
23 
24     @Override
25     public void onAttach(Context context) {
26         super.onAttach(context);
27         LogUtils.e(TAG, "onAttach: ====Fragment1");
28     }
29 
30     @Override
31     public void onCreate(Bundle savedInstanceState) {
32         super.onCreate(savedInstanceState);
33         LogUtils.e(TAG, "onCreate: ====Fragment1");
34     }
35 
36     @Override
37     public View onCreateView(LayoutInflater inflater, ViewGroup container,
38                              Bundle savedInstanceState) {
39         LogUtils.e(TAG, "onCreateView:====Fragment1 ");
40         return inflater.inflate(R.layout.fragment_fragment1, container, false);
41     }
42 
43     @Override
44     public void onActivityCreated(Bundle savedInstanceState) {
45         super.onActivityCreated(savedInstanceState);
46         LogUtils.e(TAG, "onActivityCreated:====Fragment1 ");
47     }
48 
49     @Override
50     public void onStart() {
51         super.onStart();
52         LogUtils.e(TAG, "onStart: ====Fragment1");
53     }
54 
55     @Override
56     public void onResume() {
57         super.onResume();
58         LogUtils.e(TAG, "onResume:====Fragment1 ");
59     }
60 
61     @Override
62     public void onPause() {
63         super.onPause();
64         LogUtils.e(TAG, "onPause:====Fragment1 ");
65     }
66 
67     @Override
68     public void onStop() {
69         super.onStop();
70         LogUtils.e(TAG, "onStop: ====Fragment1");
71     }
72 
73     @Override
74     public void onDestroyView() {
75         super.onDestroyView();
76         LogUtils.e(TAG, "onDestroyView: ====Fragment1");
77     }
78 
79     @Override
80     public void onDestroy() {
81         super.onDestroy();
82         LogUtils.e(TAG, "onDestroy:====Fragment1 ");
83     }
84 
85     @Override
86     public void onDetach() {
87         super.onDetach();
88         LogUtils.e(TAG, "onDetach:====Fragment1 ");
89     }
90 }

Fragment2.java

 1 package top.toly.www.fragment.life;
 2 
 3 
 4 import android.app.Fragment;
 5 import android.content.Context;
 6 import android.os.Bundle;
 7 import android.view.LayoutInflater;
 8 import android.view.View;
 9 import android.view.ViewGroup;
10 
11 import top.toly.www.fragment.R;
12 import utils.shortUtils.LogUtils;
13 
14 /**
15  * A simple {@link Fragment} subclass.
16  */
17 public class Fragment2 extends Fragment {
18     private static final String TAG = "Fragment2";
19 
20     public Fragment2() {
21         // Required empty public constructor
22     }
23 
24     @Override
25     public void onAttach(Context context) {
26         super.onAttach(context);
27         LogUtils.e(TAG, "onAttach: ====Fragment2");
28     }
29 
30     @Override
31     public void onCreate(Bundle savedInstanceState) {
32         super.onCreate(savedInstanceState);
33         LogUtils.e(TAG, "onCreate: ====Fragment2");
34     }
35 
36     @Override
37     public View onCreateView(LayoutInflater inflater, ViewGroup container,
38                              Bundle savedInstanceState) {
39         LogUtils.e(TAG, "onCreateView:====Fragment2 ");
40         return inflater.inflate(R.layout.fragment_fragment2, container, false);
41     }
42 
43     @Override
44     public void onActivityCreated(Bundle savedInstanceState) {
45         super.onActivityCreated(savedInstanceState);
46         LogUtils.e(TAG, "onActivityCreated:====Fragment2 ");
47     }
48 
49     @Override
50     public void onStart() {
51         super.onStart();
52         LogUtils.e(TAG, "onStart: ====Fragment2");
53     }
54 
55     @Override
56     public void onResume() {
57         super.onResume();
58         LogUtils.e(TAG, "onResume:====Fragment2 ");
59     }
60 
61     @Override
62     public void onPause() {
63         super.onPause();
64         LogUtils.e(TAG, "onPause:====Fragment2 ");
65     }
66 
67     @Override
68     public void onStop() {
69         super.onStop();
70         LogUtils.e(TAG, "onStop: ====Fragment2");
71     }
72 
73     @Override
74     public void onDestroyView() {
75         super.onDestroyView();
76         LogUtils.e(TAG, "onDestroyView: ====Fragment2");
77     }
78 
79     @Override
80     public void onDestroy() {
81         super.onDestroy();
82         LogUtils.e(TAG, "onDestroy:====Fragment2 ");
83     }
84 
85     @Override
86     public void onDetach() {
87         super.onDetach();
88         LogUtils.e(TAG, "onDetach:====Fragment2 ");
89     }
90 }

LifeActivity的布局文件:activity_life.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="top.toly.www.fragment.life.LifeActivity">
<LinearLayout
    android:id="@+id/ll_life_root"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/tv_title1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="title1"
        android:gravity="center"/>
    <TextView
        android:id="@+id/tv_title2"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:text="title2"
        android:gravity="center"/>
</LinearLayout>
    <FrameLayout
        android:id="@+id/fl_life_root"
        android:layout_below="@+id/ll_life_root"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>
</RelativeLayout>

Fragment1使用的布局文件:fragment_fragment1.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context="top.toly.www.fragment.life.Fragment1">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:textSize="24sp"
        android:text="@string/fragment1"/>
</RelativeLayout>

Fragment2使用的布局文件:fragment_fragment2.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             tools:context="top.toly.www.fragment.life.Fragment1">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:textSize="24sp"
        android:text="@string/fragment2"/>

</RelativeLayout>

 

以上是关于Fragment详解的主要内容,如果未能解决你的问题,请参考以下文章

Fragment生命周期详解

Fragment 使用详解

Android Fragment用法详解--静态使用Fragment

安卓Fragment使用详解

Fragment使用详解

ViewPager详解填充Fragment和懒加载