Android片段_Fragment的最详细讲解

​ Android 在 Android 3.0(API 级别 11)中引入了片段,主要是为了给大屏幕(如平板电脑)上更加动态和灵活的 UI 设计提供支持。由于平板电脑的屏幕比手机屏幕大得多,通过将 Activity 布局分成片段,您可以在运行时修改 Activity 的部分外观,并在由 Activity 管理的返回栈中保留这些更改。

创建Fragment

完整的Fragment包含两部分:

  1. Fragment对象
  2. 布局

继承Fragment. fragment还支持V4兼容包用于兼容Android3.0之前的系统, 不过现在完全不需要去兼容4.0以下的Android系统了. 所以建议使用正常包.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FragmentA extends Fragment {
/**
* 此方法是必须实现的方法, 否则此Fragment添加到Activity会Crash, 因为没有显示内容.
*
* @param inflater 内部提供的用于创建View对象的Inflater
* @param container 父控件
* @param savedInstanceState 用于恢复数据
* @return 需要返回一个布局的View对象作为显示内容
*/
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragement_a, null);
}
}

普通的布局

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="fragmentA"
/>
</LinearLayout>

Fragment是需要依附于Activity的”小Activity”, 所以需要添加到Activity中才能在界面显示. 支持两种方式添加, 其实原理都是一样.

动态添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 得到Fragment管理器
FragmentManager fragmentManager = getFragmentManager();
// 开启Fragment事务
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// 替换布局中的容器控件为Fragment的内容
fragmentTransaction.replace(R.id.activity_main, new FragmentA());
// 提交事务
fragmentTransaction.commit();
}
}

<fragment>标签

通过直接在Activity中的布局添加标签的方式

这时可以看到右侧布局预览窗口提示

这是提示你没用设置该fragment具体显示内容. 因为你没用指定该fragment标签是显示什么内容, 可以点击提示输入.

1
2
3
4
5
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.liangjingkanji.fragment.FragmentA"
tools:layout="@layout/fragement_a"/>

默认显示内容是FragmentA的内容, layout属性只是预览效果, 加与不加不影响实际效果.

关键类

Fragment

得到依附Activity实例

1
Activity getActivity ()

转场动画

这是为了支持Android5.0引入的Material Design过渡动画效果而添加的方法

1
2
boolean getAllowEnterTransitionOverlap ()
boolean getAllowReturnTransitionOverlap ()

得到转场动画

1
2
3
Transition getEnterTransition ()
Transition getExitTransition ()
Transition getReturnTransition ()

设置转场动画

1
2
3
void setEnterTransition (Transition transition)
void setExitTransition (Transition transition)
void setReturnTransition (Transition transition)

Fragment的嵌套

得到FragmentManager

Fragment支持嵌套使用, 而该方法能得到Fragment内部的Fragment的管理器

1
FragmentManager getChildFragmentManager ()

该方法是得到把自己加到Activity里面的那个FragmentManager

1
FragmentManager getFragmentManager ()
得到父Fragment
1
Fragment getParentFragment ()

Fragment的子类

Fragment的直接和间接的子类有几十个. 我后面慢慢补充吧. 其实大概用法和内容都差不太多.

DialogFragment

看我的一篇专门介绍Android的对话框文字.

FragmentManager

开启事务

Fragment是需要FragmentTransaction事务创建

1
FragmentTransaction beginTransaction ()

得到Fragment

通过tag标签得到当前Activity显示的Fragment对象

1
Fragment findFragmentByTag (String tag)

通过id找到Fragment

1
Fragment findFragmentById (int id)

返回栈

得到当前返回栈的Fragment数量

1
int getBackStackEntryCount ()

弹出返回栈, 相当于模拟按下返回键

1
void popBackStack ()

监听返回栈的改变

1
void addOnBackStackChangedListener (FragmentManager.OnBackStackChangedListener listener)

用完以后记得删除返回栈的监听器

1
void removeOnBackStackChangedListener (FragmentManager.OnBackStackChangedListener listener)

FragmentTransaction

负责Fragment的事务管理的类

添加Fragment

可以添加多个Fragment插入到Activity的容器中, 多个Fragment处于重叠状态按照添加顺序显示视图, 前两个方法实际都是调用的第三个方法.

1
2
3
4
5
6
7
8
9
FragmentTransaction add (Fragment fragment, // 该方法没有容器id相当于默认0, 所以并不会显示到界面
String tag)
FragmentTransaction add (int containerViewId,
Fragment fragment)
FragmentTransaction add (int containerViewId, // 被替换的容器ID
Fragment fragment, // 需要替换的Fragment
String tag) // 用于得到Fragment的tag

替换容器

容器即Avtivity上的布局控件, 必须是ViewGroup的子类.

添加和替换Fragment的区别: 在于替换会先删除原有的再添加. 而添加可以重复添加不会删除.

1
2
3
4
5
6
FragmentTransaction replace (int containerViewId, // 容器ID
Fragment fragment)
FragmentTransaction replace (int containerViewId,
Fragment fragment,
String tag) // 这个上面说过就不复述了

隐藏和显示Fragment

隐藏已经存在Activity上的Fragment

1
FragmentTransaction hide (Fragment fragment)

显示之前隐藏的Fragment

1
FragmentTransaction show (Fragment fragment)

分离和重建Fragment视图

分离并不是把把Fragment删除, 只是把Fragment的显示内容移除了而已.

1
2
FragmentTransaction detach (Fragment fragment) // 分离视图
FragmentTransaction attach (Fragment fragment) // 重建视图

添加到返回栈

如果执行了该方法, 在按下返回键后将退出当前Fragment而不是Activity

1
FragmentTransaction addToBackStack (String name)

过渡动画

设置默认的动画效果

支持字段:

TRANSIT_NONE 无动画效果

TRANSIT_FRAGMENT_OPEN 默认的开启动画效果

TRANSIT_FRAGMENT_CLOSE 默认的关闭动画效果

TRANSIT_FRAGMENT_FADE. 渐隐效果

1
FragmentTransaction setTransition (int transit)

设置自定义的动画效果

1
2
3
4
5
6
7
FragmentTransaction setCustomAnimations (int enter, // 进入动画xml
int exit) // 退出动画xml
FragmentTransaction setCustomAnimations (int enter,
int exit,
int popEnter, // 这是Fragment处于返回栈时的进入和退出动画
int popExit)

提交事务

这个没什么好说的. 不提交的话一切操作都无效

1
int commit ()

与Activity的交互

Fragment内部提供方法getActivity()直接获取其依附的Activity的实例. 借此数据传递或者是与该Activity上的其他Fragment进行交互都没有任何阻碍.

数据的保存和恢复

Fragment异常退出保存和恢复

保存和Activity一样

1
void onSaveInstanceState (Bundle outState)

恢复数据重写以下方法即可

1
2
void onCreate (Bundle savedInstanceState)
void onActivityCreated (Bundle savedInstanceState)

Fragment重建保存和恢复

在横竖屏切换或者Activity重建时, Activity其依附的Fragment也会同样的销毁重建. 一般会在AndroidManifest的Activity标签中加入属性android:configChanges="orientation"禁止重新创建.

以下方法进行数据的保存和获取同样可以达到数据保存的目的.

1
2
Bundle getArguments ()
void setArguments (Bundle args)

Fragment对象保存和恢复

该方法在Activity重新创建的时候能够保存和恢复Fragment的实例对象.

1
2
boolean getRetainInstance ()
void setRetainInstance (boolean retain)

使用这种方式进行实例的保存和恢复会导致Fragment的生命周期发生变化

  • onDestroy方法不会被执行, 但是onDetach会执行
  • onCreate不会执行
  • 其他生命周期方法正常

应用场景:

有时候Activity利用onSavaInstanceState来保存数据, 但是该方法是通过Bundle对象来存储数据的, Bundle对于大数据的处理会相当卡顿, 这个时候就需要用Fragment来进行保存和恢复. 如果单单是为了保存和恢复而创建的Fragment可以不需要创建布局文件. 因为不需要视图显示.

创建菜单

Fragment也提供和Activity一样的菜单创建和选择回调用法, 同样的支持向顶栏添加菜单, 不过在创建View对象之前调用setHasOptionsMenu(true);, 否则无法创建菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class FragmentA extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// 如果不设为true Fragment不会调用onCreateOptionMenu
setHasOptionsMenu(true);
return inflater.inflate(R.layout.fragement_a, null);
}
/**
* 和Activity一样, 在这里创建方法
* @param menu
* @param inflater
*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
/**
* 菜单选项被选择是回调的方法
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
}

生命周期

依附Activity生命周期

片段必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。

例如,当 Activity 暂停时,其中的所有片段也会暂停;当 Activity 被销毁时,所有片段也会被销毁。和Activity同名的方法作用也相同.

我就介绍下不同的生命周期方法吧:

  • onAttach方法:Fragment和Activity建立关联的时候调用。
  • onCreateView方法:为Fragment加载布局时调用。
  • onActivityCreated方法:当Activity中的onCreate方法执行完后调用。
  • onDestroyView方法:Fragment中的布局被移除时调用。
  • onDetach方法:Fragment和Activity解除关联的时候调用。

场景演示

切换到该Fragment:

11-29 14:26:35.095: D/AppListFragment(7649): onAttach
11-29 14:26:35.095: D/AppListFragment(7649): onCreate
11-29 14:26:35.095: D/AppListFragment(7649): onCreateView
11-29 14:26:35.100: D/AppListFragment(7649): onActivityCreated
11-29 14:26:35.120: D/AppListFragment(7649): onStart
11-29 14:26:35.120: D/AppListFragment(7649): onResume

屏幕灭掉:

11-29 14:27:35.185: D/AppListFragment(7649): onPause
11-29 14:27:35.205: D/AppListFragment(7649): onSaveInstanceState
11-29 14:27:35.205: D/AppListFragment(7649): onStop

屏幕解锁

11-29 14:33:13.240: D/AppListFragment(7649): onStart
11-29 14:33:13.275: D/AppListFragment(7649): onResume

切换到其他Fragment:

11-29 14:33:33.655: D/AppListFragment(7649): onPause
11-29 14:33:33.655: D/AppListFragment(7649): onStop
11-29 14:33:33.660: D/AppListFragment(7649): onDestroyView

切换回本身的Fragment:

11-29 14:33:55.820: D/AppListFragment(7649): onCreateView
11-29 14:33:55.825: D/AppListFragment(7649): onActivityCreated
11-29 14:33:55.825: D/AppListFragment(7649): onStart
11-29 14:33:55.825: D/AppListFragment(7649): onResume

回到桌面

11-29 14:34:26.590: D/AppListFragment(7649): onPause
11-29 14:34:26.880: D/AppListFragment(7649): onSaveInstanceState
11-29 14:34:26.880: D/AppListFragment(7649): onStop

回到应用

11-29 14:36:51.940: D/AppListFragment(7649): onStart
11-29 14:36:51.940: D/AppListFragment(7649): onResume

退出应用

11-29 14:37:03.020: D/AppListFragment(7649): onPause
11-29 14:37:03.155: D/AppListFragment(7649): onStop
11-29 14:37:03.155: D/AppListFragment(7649): onDestroyView
11-29 14:37:03.165: D/AppListFragment(7649): onDestroy
11-29 14:37:03.165: D/AppListFragment(7649): onDetach