描述
Fragment必须总是被嵌入到一个activity之中,并且fragment的生命周期直接接受其宿主activity的生命周期的影响。你可以认为fragment是activity的一个模块零件,它有自己的生命周期,接收它自己的输入的事件,并且可以在activity运行时添加或者删除。
应该将每一个fragment设计为模块化和可复用化的activity组件。也就是说,你可以在多个activity中引用同一个fragment,因为fragment定义了它自己的布局,并且使用它本身生命周期回调的行为。
生命周期
Fragment比Activity多了几个额外的生命周期回调方法:
onAttach(Activity):当Fragment和Activity发生关联时使用。
onCreateView(LayoutInflater,ViewGroup,Bundle):创建该Fragment的视图
onActivityCreate(Bundle):当Activity的onCreate()方法返回时调用
onDestoryView():与onCreateView相对应,当该Fragment的视图被移除时调用
onDetach():与onAttach()相对应,当Fragment与Activity关联被取消时调用
注意:除了onCreateView()方法,其他的所有的方法如果你重写了,必须调用父类对于该方法的实现
管理fragment生命周期与管理activity生命周期很相像,像activity一样,fragment也有三种状态:
1、Resumed:
fragment在运行中的activity中可见。
2、Paused:
另一个activity处于前台且得到焦点,但是这个fragment所在的activtiy仍然可见(前台activity部分透明,或者没有覆盖全屏)。
3、Stopped:
fragment不可见。要么宿主activity已经停止,要么fragment已经从activity上移除,但已被添加到后台栈中。一个停止的fragment仍然活着(所有的状态和成员信息仍然由系统保留着)。但是,它对于用户来讲已经不再可见,并且如果activity被杀掉,它也将被杀掉。
Fragment持久化
如果activity的进程被杀掉了,在activity被重新创建时,你恢复fragment状态。可以执行fragment的onSaveIntanceState()来保存状态(注意:fragment是在onCreate(),onCreateView()或者onActivityCreate()中进行恢复)。
在生命周期方面,activity和fragment之间一个很重要的不同就是在各自的后台栈中是如何存储的。当activity停止时,默认情况下activity被安置在由系统管理的activity后台栈中;fragment仅当在一个事务被移除时,通过显式调用addToBackStack()请求保存的实例,该fragment才被置于由宿主activity管理的后台栈。
使用方法
静态使用:直接在xml文件中使用 fragment标签
动态使用
add()、replace()、remove()、hide()、show()
getSupportFragmentManager().beginTransaction().add(R.id.content, new FirstFragment())
.commit();
API介绍
//根据ID来找到对应的Fragment实例,主要用在静态添加fragment的布局中,因为静态添加的fragment才会有ID
1、fragmentManager.findFragmentById();
//根据TAG找到对应的Fragment实例,主要用于在动态添加的fragment中,根据TAG来找到fragment实例
2、fragmentManager.findFragmentByTag();
//获取所有被ADD进Activity中的Fragment
3、fragmentManager.getFragments();
//替换containerViewId中的fragment实例,注意,它首先把containerViewId中所有fragment删除,然后再add进去当前的fragment
4、replace(int containerViewId, Fragment fragment);
//将一个fragment实例添加到Activity容器的最上层
5、add(int containerViewId, Fragment fragment, String tag);
//从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
6、remove(Fragment fragment);
//隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
7、hide(Fragment fragment)
//显示之前隐藏的Fragment
8、show(Fragment fragment)
Fragment回退栈
类似与Android系统为Activity维护一个任务栈,我们也可以通过Activity维护一个回退栈来保存每次Fragment事务发生的变化。
如果你将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。
//添加方法
fragmentTransaction.addToBackStack(String)
ex:
FragmentTwo fTwo = new FragmentTwo();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.replace(R.id.id_content, fTwo, "TWO");
tx.addToBackStack(null);
tx.commit();
把FragmentTwo加入回退栈,再使用replace方法替换,
由于FragmentTwo加入回退栈,之前加入的FragmentOne实例不会被销毁。
在创建Fragment时要传入参数
通过Arguments创建Fragment,不建议通过为Fragment添加带参数的构造函数
public class ContentFragment extends Fragment {
private String mArgument;
public static final String ARGUMENT = "argument";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// mArgument = getActivity().getIntent().getStringExtra(ARGUMENT);
Bundle bundle = getArguments();
if (bundle != null)
mArgument = bundle.getString(ARGUMENT);
}
/**
* 传入需要的参数,设置给arguments
* @param argument
* @return
*/
public static ContentFragment newInstance(String argument) {
Bundle bundle = new Bundle();
bundle.putString(ARGUMENT, argument);
ContentFragment contentFragment = new ContentFragment();
contentFragment.setArguments(bundle);
return contentFragment;
}
}
Fragment、Viewpager、懒加载
1、FragmentPagerAdapter:对于不再需要的fragment,选择调用detach方法,仅销毁视图,并不会销毁fragment实例。
2、FragmentStatePagerAdapter:会销毁不再需要的fragment,当当前事务提交以后,会彻底的将fragment从当前Activity的FragmentManager中移除。
3、懒加载,核心方法是 setUserVisibleHint()
public class BaseLazyLoadFragment extends Fragment {
private boolean mIsInit = false;//数据是否加载完成
private boolean mIsPrepared = false;//UI是否准备完成
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mRootView = inflater.inflate(R.layout.fragment_first, container, false);
mIsPrepared = true;
lazyLoad();
return mRootView;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
lazyLoad();
}
}
public void lazyLoad() {
if (getUserVisibleHint() && mIsPrepared && !mIsInit) {
// 异步初始化,在初始化后显示正常UI
loadData();
}
}
private void loadData() {
new Thread() {
public void run() {
// 1. 加载数据
// 2. 更新UI
// 3. mIsInit = true
mIsInit = true;
}
}.start();
}
}
多个Fragment重叠
原因1:横竖屏切换,造成Fragment重新实例化。
原因2:按下Home键,Activity处于后台,由于内存不足被销毁,重新唤醒时Fragment重新实例化。
注:出现的原因是在 API24 之前的 v4包 的源码问题,
解决方案:通过检查onCreate的参数Bundle savedInstanceState就可以判断,当前是否发生Activity的重新创建:
默认的savedInstanceState会存储一些数据,只有在savedInstanceState==null时,才进行创建Fragment实例:
public class MainActivity extends Activity {
private static final String TAG = "FragmentOne";
private FragmentOne mFOne;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, "ONE");
tx.commit();
}
}
}