Fragment 的含义
Fragment 表示 FragmentActivity 中的行为或界面的一部分。可以在一个 Activity 中组合多个片段,从而构建多窗格界面;也可以在多个 Activity 中重复使用某个片段。可以将 Fragment 视为 Activity 的模块化组成部分。
fragment 特点:
- Fragment具有自己的生命周期,能接收自己的输入事件,并且可以在 Activity 运行时添加或移除片段(这有点像可以在不同 Activity 中重复使用的“子 Activity”)。
- Fragment 必须始终托管在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。
- 当 Activity 暂停时,Activity 的所有片段也会暂停;当 Activity 被销毁时,所有片段也会被销毁。
- 不过,当 Activity 正在运行(处于已恢复生命周期状态)时,可以独立操纵每个片段,如添加或移除 Fragment。当执行此类片段事务时,也可将其添加到由 Activity 管理的Back Stack中,Activity 中的每个Back Stack 条目都是一条已发生片段事务的记录。借助返回栈,用户可以通过按返回按钮回到上一个Fragment。
- Fragment 也有自己独立的Layout文件和class文件
- Fragment 和 Activity 是多对多的关系:一个 Fragment 可以包含在多个不同的Activity中,一个Activity中可以包含多个不同的Fragment
Fragment 使用方法
1. 生成 Fragment:
- 构造一个 Fragment 的子类
- 在这个子类中复写 onCreateView() 方法,在此方法中 通过 inflater 类调用layout文件生成一个 Fragment。
示例代码:
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_1,container,false);
return view;
}
2. 将 Fragment 添加到 Activity:
- 将 Fragment 作为 Activity 布局的一部分添加到 Activity 中,其位于 Activity 视图层次结构的某个 ViewGroup 中,并且 Fragment 会定义其自己的视图布局,可以在 Activity 声明一个 FramLayout 作为 Fragment 容器,利用 java 代码将其插入容器:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_container);
fragmentManager = getSupportFragmentManager();
fragmentTransaction = fragmentManager.beginTransaction();
if(findViewById(R.id.fl_Container1) != null){ //确认有一个Fragment容器
if(savedInstanceState != null){ //如果activity是resumed,再生成一个Fragment会覆盖原来的Fragment
return;
}
fragment_1 = new Fragment_1();
//实例化一个自定义Fragment类的对象,并将此对象添加到容器Activity中
fragmentTransaction.add(R.id.fl_Container1,fragment_1).commitAllowingStateLoss();
//调用commit方法后才会生效,commitAllowingStateLoss宽容显示,允许一些横竖屏幕切换等情况下会出现的错误。
}
}
-
也可以通过在 Activity 的布局文件中声明 Fragment,将其作为 元素插入的 Activity 布局,或者通过将其添加到某个现有的 ViewGroup,具体代码如下:
` <fragment android:name = "fragment所在文件路径"/>`
如果用<fragment>方法添加到Activity,就无法在运行时移除或替换此Fragment。
3. 在运行过程中操作 Fragment
如要管理 Activity 中的片段,就需使用 FragmentManager。如要获取它,需要从 Activity 类中调用 getSupportFragmentManager() 方法。
使用 FragmentManager 执行的如下操作进行 Fragment 操作:
- 通过 findFragmentById()(针对在 Activity 布局中提供界面的片段)或 findFragmentByTag()(针对提供或不提供界面的片段)获取 Activity 中存在的片段。
- 通过 popBackStack()(模拟用户发出的返回命令)使片段从返回栈中弹出。
- 也可使用 FragmentManager 打开一个 FragmentTransaction,通过它来执行其他 Fragment 操作,如添加和移除片段。
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Activity 与 Fragment,Fragment 与 Fragment 的通信
实现思路:
在 Fragment 类中定义一个回调接口,并要求宿主 Activity 实现此接口。当 Activity 通过该接口收到回调时,可根据需要与 Activity 或布局中的其他 Fragment 共享这些信息。
Activity 与 Fragment 通信:
- 在 Fragment 中定义回调接口,在接口中定义的方法是通信的具体实现方法。
public interface onMessageReader {
public void onMessageReade(String message);
}
- 在宿主 Activity 中实现回调接口,并复写接口中的方法。
@Override
public void onMessageReade(String message) {
mTvmessage = findViewById(R.id.tv_message);
mTvmessage.setText(message);
}
- 利用 Fragment 类中的 onAttach() 回调函数,此函数在 Fragment 被添加到宿主 Activity 时会返回此 Activity 对象,利用此对象实例化一个回调接口,这样就可以通过这个实例实现 Fragment 和 Activity的通信。同时通过try catch 结构保证宿主已经实现了回调接口。
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
Activity activity = (Activity) context;
//使用onAttach方法传过来的context参数实例化接口,使用此接口内的函数在Fragment和Activity之间通信
try { //check实现接口是是否override了Read方法
onMessageReader = (Fragment_1.onMessageReader) activity;
}catch (ClassCastException e){
throw new ClassCastException(activity.toString() + "must override onMessageReader...");
}
}
Fragment 与 Fragment 之间的通信:
Fragment 之间是无法直接通信的,只有同一个宿主 Activity 下的 Fragment 之间可以借助宿主实现通信,具体实现方法建立在 Fragment 和 Activity 的通信之上,在实现回调接口中的通信方法时,构造一个 Bundle 类的对象,将 Fragment A 的信息以键值对的方式传送给 Bundle 对象,最后调用 Fragment 类的 setArgumnet() 方法将信息传送给 Fragment B ,Fragment B 调用 getArgument() 方法就可以取出信息使用。
@Override
public void onMessageReade(String message) {
Fragment_2 fragment_2 = new Fragment_2();
fragmentManager.beginTransaction().add(R.id.fl_Container3,fragment_2).commit();
Bundle bundle = new Bundle();
bundle.putString("Title",message);
fragment_2.setArguments(bundle);
}