1. Fragment 是什么?
Fragment 直译为 “碎片 ”或 “片段”,是一种可嵌入在 Activity 中的 UI 片段,可以看作是 Activity 的模块化部分,用于构建动态和灵活的用户界面,更加合理和充分利用大屏幕的空间。
Fragment 不能独立存在,必须嵌入到 Activity 中,其生命周期与所在的 Activity 紧密相关。
Fragment 用法类似于一个自定义控件。
主要特点:
模块化:Fragment 允许开发者将应用界面划分为多个独立、可重用的部分,每个 Fragment 都可以定义自己的布局和行为。
灵活性:Fragment 可以在运行时动态添加到 Activity 布局中,也可以在不同的 Activity 中重复使用,从而实现灵活的UI布局和界面复用。
适应不同屏幕尺寸:Fragment 非常适合在大屏幕设备(如平板电脑)上实现多窗格UI设计,同时也可以在小屏幕设备上适配不同的屏幕尺寸和方向。
生命周期管理:Fragment 拥有自己的生命周期,与 Activity 的生命周期类似但更为复杂。系统负责管理 Fragment 的生命周期,开发者可以在相应的生命周期回调方法中进行初始化、视图创建、数据加载等操作。
2. Fragment 的使用方式
2.1 静态添加 Fragment
新建左侧 Fragment 布局 left_fragment.xml
,新建右侧 Fragment 布局 right_fragment.xml
。
新建一个 LeftFragment 类,继承自 Fragment(AndroidX) 类,将定义的布局动态加载进来。
java 代码解读复制代码public class LeftFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.left_fragment,container,false);//动态加载布局
return view;
}
}
新建一个 RightFragment 类。
修改 activity_main.xml
,需要通过 android: name 显式声明要添加的 fragment 类名,一定要加类的包名:
xml 代码解读复制代码"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:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.trainning.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.trainning.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
LinearLayout>
2.2 动态添加 Fragment
新建 another_right_fragment.xml
,新建 AnotherRightFragment
,代码省略。
修改 activity_main.xml
,
xml 代码解读复制代码"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:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.trainning.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>
在 Activity 中动态添加 Fragment:
- 创建待添加的 fragment 实例。
- 获取 FragmentManager,调用 getSupportFragmentManager。
- 开启一个事务 beginTransaction。
- 替换 fragment,replace。
- 提交事务 。
java 代码解读复制代码public class NormalFragmentActivity extends AppCompatActivity {
private Button leftFragmentButton;
private View leftFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal_fragment);
leftFragment = findViewById(R.id.left_fragment);
leftFragmentButton = leftFragment.findViewById(R.id.left_fragment_button);
replaceFragment(new RightFragment());
leftFragmentButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
replaceFragment(new AnotherRightFragment());
}
});
}
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();// 获取 FragmentManager
FragmentTransaction transaction = fragmentManager.beginTransaction();// 开启一个事务 beginTransaction()
transaction.replace(R.id.right_layout, fragment);
transaction.commit();
}
}
FragmentManager 用于管理 Fragment 的生命周期、交互和事务。Activity 是 FragmentManager 的宿主环境类。
FragmentTransaction:提供了一系列的方法来执行对 Fragment 的事务性操作,用来管理 Fragment 的添加、移除、替换以及执行其他操作。
事务的提交是通过调用 commit
方法完成的。一旦事务被提交,系统就会按照你指定的操作顺序来更新Fragment的状态。
“事务”(Transaction)是指一系列对Fragment进行的操作,这些操作被封装在一个单独的执行单元中,并且要么全部成功执行,要么全部回滚(即不执行任何操作)。这种机制确保了Fragment状态的一致性,防止了因部分操作失败而导致的界面不一致或应用崩溃。
3. 在 Fragment 里模拟返回栈
模拟返回栈对于 Fragment 的管理是非常重要的。通过模拟返回栈,你可以让用户在 Fragment 之间进行导航,并且能够通过按下 back 键返回到之前的 Fragment 状态,而不是直接关闭 Activity。
在 Fragment 事务中,你使用 addToBackStack()
方法将 Fragment 事务添加到返回栈中。这样,当用户按下后退键时,系统会自动回退到上一个 Fragment。
java 代码解读复制代码private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.right_layout,fragment);
transaction.addToBackStack(null); //接受一个名字描述返回栈的状态
transaction.commit();
}
addToBackStack 可以传入一个 null 作为名称,或者传入一个唯一的字符串来标识这个返回栈条目,如:
java 代码解读复制代码fragmentTransaction.addToBackStack("my_unique_back_stack_entry");
这个名称在调试时可能会派上用场,它可以帮助你识别返回栈中的不同条目。在大多数情况下,传入 null 就足够了,因为系统会自动为每个返回栈条目分配一个唯一的 ID。
4. Fragment 和 Activity 之间的通信
在 Activity 中获得 Fragment 实例:
java 代码解读复制代码LeftFragment leftFragment = (LeftFragment)getSupportFragmentManager().findFragmentById(R.id.left_fragment);
在 Fragment 中获得相关联 Activity 的实例:
java 代码解读复制代码NormalFragmentActivity activity = (NormalFragmentActivity) getActivity();
Fragment 中需要使用 Context 对象时,也可以使用 getActivity()方法。
下面介绍两种常用的通信方式:
4.1 Activity 使用 Bundle 向 Fragment 传递数据
在 Activity 中创建 Fragment 实例并传递数据:
java 代码解读复制代码MyFragment myFragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("key", "value");
myFragment.setArguments(bundle);
replaceFragment(myFragment);
在 Fragment 中接收数据:
java 代码解读复制代码@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null) {
String value = arguments.getString("key");
// 使用传递过来的数据
}
}
4.2 Fragment 使用接口向 Activity 传递数据
定义接口:
java 代码解读复制代码public interface IFragmentCallback {
void onFragmentChanged();
}
Activity:
java 代码解读复制代码public class FragmentActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_normal_fragment);
LeftFragment leftFragment = new LeftFragment();
leftFragment.setFragmentCallback(new IFragmentCallback() {
@Override
public void onFragmentChanged() {
Log.i("this", "click button in the fragment");
}
});
}
}
Fragment:
java 代码解读复制代码public class LeftFragment extends Fragment {
private IFragmentCallback fragmentCallback;
View view;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.left_fragment, container,false);
}
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fragmentCallback.onFragmentChanged();
}
});
return view;
}
public void setFragmentCallback(IFragmentCallback fragmentCallback) {
this.fragmentCallback = fragmentCallback;
}
}
当点击 Fragment 中的按钮时,Activity 中就会收到回调,并可以处理相应的逻辑。
除此之外,activity 与 fragment 之间的通信还可以采用其他方案,如 EventBus、LiveData 等,其本质上都是使用了观察者模式。
5. Fragment 的生命周期
Fragment 的生命周期可参考:fragment 生命周期 | Android Developers ,此文章中进行了详细解析。
后续会专门出文章对 Fragment 进行源码分析。
评论记录:
回复评论: