Fragment 基础认知
1. 定义与作用
Fragment 代表了 Activity 里的一部分用户界面或者功能。它有独立的生命周期,能接收输入事件,还能在 Activity 运行期间添加或移除。其主要作用是实现界面模块化,提升代码复用率,以及让界面在不同屏幕尺寸上有更好的适配性。
2. 核心特性
- 具备独立的生命周期,和 Activity 的生命周期相互关联。
- 可以在多个 Activity 中重复使用。
- 能通过 FragmentManager 进行管理,支持添加、替换等操作。
- 可以和宿主 Activity 以及其他 Fragment 进行通信。
Fragment 生命周期
Fragment 的生命周期比 Activity 更为复杂,主要方法如下:
1. 关键回调方法
onAttach(Context context):当 Fragment 和 Activity 建立关联时调用。onCreate(Bundle savedInstanceState):系统创建 Fragment 时调用。onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState):用于创建 Fragment 的视图。onActivityCreated(Bundle savedInstanceState):宿主 Activity 完成onCreate()后调用。onStart():Fragment 对用户可见时调用。onResume():Fragment 开始和用户交互时调用。onPause():Fragment 暂停和用户交互时调用。onStop():Fragment 对用户不可见时调用。onDestroyView():Fragment 的视图被销毁时调用。onDestroy():Fragment 被销毁时调用。onDetach():Fragment 和 Activity 的关联解除时调用。
2. 与Activity生命周期关系
Activity 的生命周期会直接影响 Fragment 的生命周期。比如,当 Activity 执行 onPause() 时,它所包含的 Fragment 也会执行 onPause()。
Fragment 创建与使用
1. 继承Fragment
要继承 Fragment(或 androidx.fragment.app.Fragment)类,并且重写 onCreateView() 方法。
public class FirstFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
2. 在布局中静态添加 Fragment
在 Activity 的布局文件里使用 <fragment> 标签。
<androidx.fragment.app.FragmentContainerView
android:id="@+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
3. 在代码中动态添加 Fragment
借助 FragmentManager 和 FragmentTransaction 来实现。
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.my_fragment, new SecondFragment());
fragmentTransaction.commit();
Fragment 间通信
1. Fragment与Activity通信
- 接口回调:Fragment 定义接口,Activity 实现该接口。
public class FirstFragment extends Fragment {
private OnFragmentInteractionListener mListener;
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_first, container, false);
Button button = view.findViewById(R.id.send_button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String data = "Hello from fragment";
sendDataToActivity(data);
}
});
return view;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(String data);
}
// 在需要通信的地方调用
private void sendDataToActivity(String data) {
if (mListener != null) {
mListener.onFragmentInteraction(data);
}
}
public class MainActivity extends AppCompatActivity implements FirstFragment.OnFragmentInteractionListener{
private TextView tvData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
tvData = findViewById(R.id.tv_data);
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.my_fragment, new FirstFragment());
fragmentTransaction.commit();
}
@Override
public void onFragmentInteraction(String data) {
tvData.setText(data);
}
}
- ViewModel:使用
ViewModel实现数据共享。
public class SharedViewModel extends ViewModel {
private MutableLiveData<String> data = new MutableLiveData<>();
public LiveData<String> getData() {
return data;
}
public void setData(String newData) {
data.setValue(newData);
}
}
public class MainActivity extends AppCompatActivity {
private TextView tvData;
private SharedViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
tvData = findViewById(R.id.tv_data);
viewModel = new ViewModelProvider(this).get(SharedViewModel.class);
viewModel.getData().observe(this, data -> {
// 当数据变化时,更新 Activity 的 UI
Log.d("MainActivity", "Received data: " + data);
tvData.setText(data);
Toast.makeText(this, "Activity received: " + data, Toast.LENGTH_SHORT).show();
});
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.my_fragment, new SecondFragment());
fragmentTransaction.commit();
}
}
public class SecondFragment extends Fragment {
private SharedViewModel viewModel;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_second, container, false);
// 初始化 ViewModel
viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
// 观察 ViewModel 中的数据变化
viewModel.getData().observe(getViewLifecycleOwner(), data -> {
// 当数据变化时,更新 Fragment 的 UI
Log.d("FirstFragment", "Received data: " + data);
TextView textView = view.findViewById(R.id.fragment_text);
textView.setText(data);
});
// 添加一个按钮点击事件,用于发送数据到 ViewModel
Button sendButton = view.findViewById(R.id.send_button);
sendButton.setOnClickListener(v -> {
String data = "Hello from Fragment";
viewModel.setData(data);
});
return view;
}
}
2. Fragment之间通信
- 通过共同的 Activity 作为中介。
- 利用
ViewModel共享数据。
public class MyFragment extends Fragment {
private SharedViewModel viewModel;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// 获取 Activity 作用域的 ViewModel
viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
// 发送数据
button.setOnClickListener(v -> {
viewModel.setData("Hello from MyFragment");
});
}
}
// AnotherFragment.java
public class AnotherFragment extends Fragment {
private SharedViewModel viewModel;
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// 获取相同的 ViewModel 实例
viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
// 观察数据变化
viewModel.getData().observe(getViewLifecycleOwner(), data -> {
textView.setText(data);
});
}
}
Fragment事务操作
1. 事务基础操作
1. 事务的本质
- 原子性操作集:一组对 Fragment 的操作(如添加、替换)可作为一个单元执行。
- 支持回退栈:通过
addToBackStack()可模拟 “返回” 行为。
2. 获取FragmentManager
- Activity中
FragmentManager manager = getSupportFragmentManager(); // AndroidX
- Fragment中
FragmentManager childManager = getChildFragmentManager(); // 子 Fragment 管理
2. 核心事务操作
1. 添加Fragment
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.my_fragment, new SecondFragment());
fragmentTransaction.commit();
2. 替换Fragment
fragmentTransaction.replace(R.id.my_fragment,new ThirdFragment()); // 等价于先 remove() 再 add()
3. 移除Fragment
Fragment second = supportFragmentManager.findFragmentByTag("Second");
if(second != null){
fragmentTransaction.remove(second);
}
4. 隐藏/显示Fragment
fragmentTransaction.hide(second);
fragmentTransaction.show(second);
5. 附加/分离Fragment
transaction.detach(fragment); // 销毁视图,但保留实例和状态
transaction.attach(fragment); // 重新创建视图
3. 事务回退栈管理
1. 添加到回退栈
transaction.addToBackStack("MyTransaction"); // 按名称入栈
transaction.commit();
2. 出栈操作
manager.popBackStack(); // 弹出栈顶事务
manager.popBackStack("MyTransaction", 0); // 弹出指定事务及以上所有项
4. 事务执行时机
- 同步执行
transaction.commitNow(); // 同步执行,不支持回退栈
- 异步执行
transaction.commit(); // 在下一帧执行,允许与其他事务合并
- 安全提交
if(supportFragmentManager.isStateSaved()){
fragmentTransaction.commit();
}
- 适用场景:在 Activity/Fragment 状态已保存后(如 onSaveInstanceState 后)避免提交事务。
Fragment动画与过渡效果
1. 传统动画
transaction.setCustomAnimations(
R.anim.enter_from_right, // 进入动画
R.anim.exit_to_left, // 退出动画
R.anim.pop_enter, // 回退栈进入动画
R.anim.pop_exit // 回退栈退出动画
);
2. 过渡动画
// 在 Fragment 中设置
setEnterTransition(new Slide(Gravity.END));
setExitTransition(new Fade());
// 或在事务中设置
transaction.setReorderingAllowed(true); // 优化过渡效果
最佳实践
1. 避免状态丢失
- 错误场景:在 Activity 的
onSaveInstanceState()后提交事务。 - 解决方案:使用
commitAllowingStateLoss()(谨慎使用)或检查状态:if (!isStateSaved()) { transaction.commit(); }
2. 使用合适的容器
- 推荐
FragmentContainerView:<androidx.fragment.app.FragmentContainerView android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" />
3. 谨慎使用回退栈
- 避免过度入栈导致内存占用过高。
- 使用
getBackStackEntryCount()监控栈深度。
4. 处理配置变更*
-
优先让系统自动恢复 Fragment 状态,而非手动管理。
-
避免在
onCreate()中重复添加 Fragment:if (savedInstanceState == null) { manager.beginTransaction() .add(R.id.container, new MyFragment()) .commit(); }