知识点整理
4.1基本概念
● Fragment是依赖于Activity的,不能独立存在的。
● 一个Activity里可以有多个Fragment。
● 一个Fragment可以被多个Activity重用。
● Fragment有自己的生命周期,并能接收输入事件。
● 我们能在Activity运行时动态地添加或删除Fragment。
4.2生命周期
Fragment的生命周期和Activity类似,但比Activity的生命周期复杂一些,基本的生命周期方法如下图:
4.2.1 Fragment 生命周期中的每个方法的意义与作用
●onAttach():Fragment和Activity相关联时调用。且仅调用一次,可以通过该方法获取Activity引用,还可以通过getArguments()获取参数。 调用此方法时,Fragment与Activity已完成绑定。
● onCreate():Fragment最初创建时调用。初始化Fragment,可通过savedInstanceState 获取之前保存的值。
● View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
在准备绘制Fragment界面时调用,返回值为Fragment要绘制布局的根视图,当然也可以返回null。注意使用inflater构建View时一定要将attachToRoot指明false,因为Fragment会自动将视图添加到container中,attachToRoot为true会重复添加报错。onCreateView并不是一定会被调用,当添加的是没有界面的Fragment就不会调用,比如调用FragmentTransaction的 add(Fragment fragment, String tag)方法。
● onActivityCreated():当Activity完成onCreate()时调用。
● onStart():当Fragment可见时调用。Fragment有不可见变为可见状态
● onResume():当Fragment可见且可交互时调用。ragment处于活动状态,用户可与之交互。
● onPause():当Fragment不可交互但可见时调用。
● onStop():当Fragment不可见时调用。
● onDestroyView():当Fragment的UI从视图结构中移除时调用。
● onDestroy():销毁Fragment时调用。
● onDetach():当Fragment和Activity解除关联时调用。
上面的方法中,只有onCreateView()在重写时不用写super方法,其他都需要。
图中有一条从onDestroyView指向onCreatedView的线,意思是Fragment从back栈(存放Fragment的栈)回到前台时经历的生命周期。
4.2.2Activity 生命周期对Fragment生命周期的影响
将Fragment生命周期中每个回调单独讲完之后,下面就来看看Fragment生命周期和Activity生命周期之前的联系,这里也有一张十分经典的官方图。
可以十分明了的看到,当Activity处于不同生命周期时Fragment生命周期的流程。需要关注一下两者生命周期顺序问题,其中onCreate、onStart、onResume都是Activity先调用之后才是Fragment,onPause、onStop、onDestroy(在Fragment中是onDetach),是先Fragment调用之后才是Activity。
Fragment相关操作对生命周期的影响
添加Fragment可以分为静态添加和动态添加两大类。
● 静态添加是在XML中直接添加Fragment,简单方便,缺点是添加之后不能在删除。
● 动态添加是在代码中FragmentManger使用一系列FragmentTransaction事务操作动态控制,灵活多变。一般都是使用动态添加,下面就讲讲动态添加有关的生命周期。
1.add:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume
2.remove:onPause->onStop->onDestroyView->onDestroy->onDetach
3.show:onHiddenChanged(boolean hidden) hidden为false
4.hide:onHiddenChanged(boolean hidden) hidden为true
5.replace:旧Fragment的remove生命周期->新Fragment的add生命周期
6.replace+addToBackStack:onPause->onStop->onDestroyView->新Fragment的add生命周期
之后点击back:新Fragment的remove->onCreateView->onViewCreated->onActivityCreated->onStart->onResume 就是第一张图的线
7. detach:onPause->onStop->onDestroyView 可以看到只是视图被移除,Fragment关联状态还是不变,还是处于FragmentManger的管理下
8.FragmentTransaction.attach(Fragment var1):onStart->onResume->onCreateView
4.2.1静态加载碎片
使用标签在布局中添加碎片:
- android:name属于来显式指明要添加的碎片类名
- 添加id 属性(不添加会报错)
静态加载碎片直接在xml,中加载
例子:在Activiy中左右加载两个碎片
left.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00ff00">
</LinearLayout>
fragement_left.java
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left,container,false);
return view;
}
right.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
fragement_right.java
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.right,container,false);
return view;
}
主界面加载:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/left_fragement"
android:layout_width="0dp"
android:name="com.example.myapplication.frame_left"
android:layout_height="match_parent"
android:layout_weight="1">
</fragment>
<fragment
android:id="@+id/right_fragement"
android:layout_width="0dp"
android:name="com.example.myapplication.frame_right"
android:layout_height="match_parent"
android:layout_weight="1">
</fragment>
</LinearLayout>
效果 :
4.2.2 动态添加碎片
碎片不仅可以在xml中静态加载,还可以在程序运行时动态地添加到活动中。
动态添加碎片的步骤:
● 创建待添加的碎片实例
● 获取FragementManager在活动中调用getSupportFragmentManager()方法来获取
● 开启事务,调用beginTransaction()方法来开启一个事务
● 向容器内添加或替换碎片,一般使用replace()方法实现,需要传入容器的id和待添加的碎片实例
● 提交事务,调用commit()方法来完成
在上面的基础上,新建一个another_fragement.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffff00"
android:orientation="vertical">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textSize="20sp"
android:text="This is another right fragment"/>
</LinearLayout>
创建AnotherRightFragment类: 将布局引进来
public class AnotherRightFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.another_right_fragment, container, false);
return view;
}
}
修改activity_main.xml文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.fragmenttest.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/right_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
在代码中向FrameLayout里添加内容,从而实现动态添加碎片的功能。
修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
replaceFragment(new RightFragment());
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
replaceFragment(new AnotherRightFragment());
break;
default:
break;
}
}
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_layout, fragment);
transaction.commit();
}
}
通过点击左侧fragement中的button ,来实现右侧fragement 进行切换
效果图:
运行程序,效果图如下:
4.2.3 在碎片中模拟返回栈
上面通过点击按钮添加一个碎片后,如果此时按下Back键程序就会直接退出。如果想要模范返回栈的效果,返回到上一个碎片,则需要在提交事务之前调用addToBackStack()方法。
addToBackStack中一般填写null
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_layout, fragment);
transaction.addToBackStack(null);
transaction.commit();
}