简单示例
说明
-
Activity通过一个FrameLayout来安排Fragment在Activity中的位置:FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.add(R.id.fragment_container, fragment).commit(); - 可以用
FragmentManager通过Fragment对应的FrameLayout的ID来获取Fragment:Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container); - 创建
Fragment的时候应该先从FragmentManager中查找,找不到再创建。因为Activity会在配置改变(如横竖屏转换)时销毁重建,此时Fragment不会因为Activity的销毁重建和跟着销毁重建:FragmentManager fragmentManager = getSupportFragmentManager(); // 先在FragmentManager中查找后创建的原因:Activity会因为配置改变而销毁重建,但是fragment Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container); // 获取FragmentTransaction FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); if (fragment == null) { fragment = new CrimeFragment(); fragmentTransaction.add(R.id.fragment_container, fragment).commit(); } -
Activity通过FragmentTransaction来实现运行时 添加 、 移除 、 隐藏 、 附加 、 分离 或 替换Fragment队列中的Fragment:FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); -
Activity有两种托管Fragment的方式:- 通过
FragmentTransaction,动态载入(推荐)。 - 在
Activity的 XML 文件中添加。
- 通过
activity_crime.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
fragment_crime.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
CrimeFragment.java
public class CrimeFragment extends Fragment {
// 创建数据
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
// 创建视图
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_crime, container, false);
return view;
}
}
CrimeActivity.java
public class CrimeActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime);
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragment == null) {
fragment = new CrimeFragment();
fragmentTransaction.add(R.id.fragment_container, fragment).commit();
}
}
}
FragmentTransaction切换Fragment示例
// 从Activity中获取FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// 从Activity中获取WindowManager
WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
if (screenSize.x > screenSize.y) {
// 横屏
Fragment1 fragment1 = new Fragment1();
fragmentTransaction.replace(android.R.id.content, fragment1);
} else {
// 竖屏
Fragment2 fragment1 = new Fragment2();
fragmentTransaction.replace(android.R.id.content, fragment2);
}
// 将FragmentTransaction对象压入栈中并提交
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
调用Activity
- 关于
newIntent()静态方法的详情查看Activity笔记。Intent intent = MyActivity.newIntent(getActivity(), data); startActivity(intent);
传入数据
绑定
- 给
Fragment设置argument,相当于Activity的extra数据。Bundle args = new Bundle(); args.putSerializable(/* data */); CrimeFragment fragment = new CrimeFragment(); fragment.setArguments(args);
获取
UUID id = (UUID) getArguments().getSerializable(/* data */);
返回结果
方式一:通过Activity的onActivityResult(),返回结果给Activity
-
Fragment自身无法持有返回结果,只能通过Activity设置返回结果:getActivity().setResult(Activity.RESULT_OK, /* 数据 */); - 通过重写
onActivityResult(),从被调用的Activity中获取和处理返回结果。
方式二:通过Fragment的onActivityResult(),返回结果给Fragment
- 设置目标
Fragment:FragmentManager manager = getFragmentManager(); DatePickerFragment dialog = DatePickerFragment.newInstance(/* 数据 */); dialog.setTargetFragment(/* 目标Fragment */, /* 返回结果标签 */); dialog.show(manager, /* 标签 */); - 目标
Fragment中的onActivityResult()处理返回结果:@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode != Activity.RESULT_OK) { return; } if (requestCode == /* 返回结果标签 */) { /* 处理返回结果 */ } } - 返回结果:
Intent intent = new Intent(); intent.putExtra(EXTRA_DATE, /* 数据 */); getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, intent);
创建
-
通过在
Fragment中封装newInstance静态方法来使得Fragment本身决定如何创建Fragment:public static CrimeFragment newInstance(/* data */) { Bundle args = new Bundle(); args.putSerializable(/* data */); CrimeFragment fragment = new CrimeFragment(); fragment.setArguments(args); return fragment; }
常用接口
-
findFragmentById(...):参数为装载Fragment的FrameLayout的ID。
生命周期
- 打开:
onAttachonCreateonCreateViewonActivityCreatedonStartonResume
- 进入后台:
onPauseonStop
- 进入前台:
onStartonResume
- 应用程序配置发生改变(横竖屏切换):
onPauseonStoponDestroyViewonDestroryonDetachonAttachonCreateonCreateViewonActivityCreatedonStartonResume
- 退出:
onPauseonStoponDestroyViewonDestroryonDetach
保留Fragment到Activity销毁后
- 可以通过
setRetainInstance(true)使得Fragment可以在托管者Activity销毁时仍然保留,这样Fragment的数据也会得到保留。
代码
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
注意事项
- 通常用于设备旋转这种短暂保留的情形,因为被保留的
Fragment可能会因为系统回收内存等情形被销毁,所以在保留后还要尽快被Activity重新接管。 - 无论
Fragment是否被设置保留,在Activity销毁时,Fragment的视图都会被销毁以便将来重建视图,但是设置保留Fragment的话,Fragment本身不会被销毁。 - 相对于非保留
Fragment,保留Fragment的显示非常复杂,一旦出现问题,排查起来非常耗时,能不用就不用。 - 使用保留
Fragment的原因是为了保留数据,但是onSaveInstanceState对于不可保存的对象数据(如音频播放到一半)无能为力。 - 对于需要短暂保存
Fragment数据的情形(如设备旋转),使用保留Fragment可以很便捷地解决问题,但是如果想要持久地保存数据最好使用别的方式。
常用技巧
- 把
Fragment需要暴露出去的东西,弄成一个Fragment.Callbacks,暴露给托管者Activity。 - 在
onCreate()中检查savedInstanceState是否为null,若是则代表着Fragment是第一次加载,同样的技巧在Activity中也是可用的。
注意事项
-
Activity中总是使用Fragment -
Activity中Fragment数量最好不要超过2-3个。 - 总是使用支持库版本的
Fragment:Fragment、FragmentManager、FragmentActivity。原因见此 - 相比与
onResume(),onStart()不一定会执行。 -
Fragment自身无法持有返回结果,只能通过Activity。 -
Fragment中的实例变量不可靠,生命期比Fragment长的实例变量应该尽量存在外部。 - 同一个
Activity中的不同Fragment通过getActivity()来交互。 -
Fragment不应该对托管者Activity有任何假设,以使得Fragment具有可复用性。
相关报错
-
Fragment not attached to Activity:在合适位置添加
isAdded()。如:@Override protected void onPostExecute(Void result){ if(isAdded()){ getResources().getString(R.string.app_name); } }