简单示例
说明
-
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。
生命周期
- 打开:
onAttach
onCreate
onCreateView
onActivityCreated
onStart
onResume
- 进入后台:
onPause
onStop
- 进入前台:
onStart
onResume
- 应用程序配置发生改变(横竖屏切换):
onPause
onStop
onDestroyView
onDestrory
onDetach
onAttach
onCreate
onCreateView
onActivityCreated
onStart
onResume
- 退出:
onPause
onStop
onDestroyView
onDestrory
onDetach
保留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); } }