Fragment生命周期
Fragment的生命周期跟Activity类似,跟Activity一样,Fragment也有的生命状态。
- Created
onAttach():当Fragment第一次attach到Activity。
onCreate():Fragment的初始化创建,这个回调函数调用的时候,Activity处于create的过程中,不要处理跟Activity相关的东西,比如content view。
onCreateView():实例化Fragment的View并返回。
onViewCreated():onCreateView()完成之后,会里面回调这个函数。
onActivityCreated():当Activity的onCreate()完成和Fragment的View被初始化之后,回调这个函数。 - Started
onStart():跟Activity同步,当Activity的处于start状态时,Fragment的onStart()被调用。 - Resumed
等同于Activity的Resumed的状态。当Activivty的onResume被调用时,Fragment的onResume()同时被调用。 - Paused
等同于Activity的Paused的状态。当Activivty的onPause被调用时,Fragment的onPause()同时被调用。 - Stopped
等同于Activity的Stopped状态,当Activivty的onStop被调用时,Fragment的onStop()同时被调用。 - Destroyed
onDestroyView():之前onCreateView创建出来的View被移除,下次Fragment显示的时候需要重新创建一个View。
onDestroy():当Fragment不再使用的时候会调用onDestroy。
onDetach(): Fragment从Activity中移除,detach。
跟Activity一样, 可以使用Bundle来保存状态,防止Activity被杀掉之后,我们需要恢复fragment的状态当Activity 重建之后。可以通过调用fragment’s onSaveInstanceState()函数保存,在这几个函数中恢复onCreate(), onCreateView(), or onActivityCreated()。
Fragment使用
- 通过XML Layout文件
有三种方法为Fragment提供ID:
android:id属性:唯一的id
android:tag属性:唯一的字符串
如果上面两个都没提供,系统使用容器view的ID。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="@+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
- 通过代码动态添加
动态使用Fragment就是手动在代码中添加、替换、删除Fragment。获取FragmentManager,通过事务添加或者删除Fragment,设置默认显示Fragment,开启事务transaction,提交事务。
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
管理Fragments
Fragment是通过 FragmentManager来管理,通过getFragmentManager()来获取,通过FragmentManager可以做以下事情:
- 通过findFragmentById()或者findFragmentByTag()来获取Fragment
- 通过popBackStack()出栈back stack。
- 通过addOnBackStackChangedListener()来注册监听back stack的变化。
FragmentTransaction事务来管理Fragment的变化,一个事务可以处理多个事情,比如add(), remove(), and replace()。之后调用commit来提交这个事务。
在提交事务之前,可以通过“addToBackStack()”把事务加到back stack中,这个back stack通过Activity来管理。通过返回键可以反转事务然后返回到前一个fragment的状态。
举例使用addToBackStack()
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().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保存状态前提交事务。如果是在activity保存状态之后提交事务,就是抛一个Exception,这是因为activity的状态会被丢失在事务提交之后。这个情况下使用commitAllowingStateLoss()来表示你可以放弃这次事务的提交。
Transaction的几个方法执行流程:
transaction.show(fragment),transaction.hide(fragment), 显示或者隐藏Fragment,onHiddenChanged()回调函数会被调用;
API 23上不会调用onAttach方法,需要在Support包上使用。
remove方法执行后Fragment的回调流程:
onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
add方法执行后的Fragment回调函数:
onAttach -> onCreate-> onCreateView -> onActivityCreated -> onStart -> onResume
detach方法执行后的Fragment回调函数,Fragment不会销毁:
onPause -> onStop -> onDestroyView
attach方法执行后的Fragment回调函数:
onCreateView -> onActivityCreated -> onStart -> onResume
不添加到back stack, replace方法执行后的回调函数,replace相当于向调用remove,再调用add:
旧Fragment:onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
新Fragment:onAttach -> onCreate-> onCreateView -> onActivityCreated -> onStart -> onResume
添加到back stack, replace方法执行后的回调函数,旧Fragment不会销毁:
onPause -> onStop -> onDestroyView
调用popBackStack,Fragment回调流程:
onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
setCustomAnimations方法可以设置Fragment在FragmentManager中的切换动画。参考:https://developer.android.com/training/animation/cardflip.html?hl=id
与Activity交互
Fragment可以通过getActivity()来获取到关联的Activity。
Activity可以通过FragmentManager调用findFragmentById() or findFragmentByTag()来获取相关的Fragment。
给Activity创建一个事件回调函数
如果Fragment需要与Activity共享事件,可以在Fragmeng中申明一个接口,然后相关的Activity来实现。在onAttach的时候,把Activity赋值给Fragment中的接口变量。
public static class FragmentA extends ListFragment {
...
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnArticleSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");
}
}
...
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
Fragment在ViewPager中的生命周期
使用FragmentPagerAdapter
FragmentPagerAdapter把每一页都表现为一个Fragment,并且会被保留在fragment manager 中。
FragmentPagerAdapter比较适合于少量静态Fragment之间的切换, 比如一套Tab。每一个用户浏览过的Fragment会被保存在内存中,即使它的view已经destroy了。这会导致 使用大量的内存,因为Fragment的实体会被保存到任意的状态。
假设ViewPager中有三个Fragment,分别为A,B,C。
第一次进入ViewPager时:ViewPager会初始化两个Fragment,也就是A和B。那么A,B此时的生命周期调用流程为:
A: setUserVisibleHint(isVisibleToUser=false)->onAttach ->onCreate -> setUserVisibleHint(isVisibleToUser=true) -> onCreateView -> onActivityCreated -> onStart -> onResume
B: setUserVisibleHint(isVisibleToUser=false)->onAttach ->onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume
当ViewPager滑动一页的时候,也就是当前页从A到了B,那么A、B、C的生命周期的调用流程为:
A:setUserVisibleHint(isVisibleToUser=false)
B: setUserVisibleHint(isVisibleToUser=true)
C:setUserVisibleHint(isVisibleToUser=false)->onAttach ->onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume
当ViewPager的当前页从B换到C的时候,那么A、B、C的生命周期的调用流程为:
A:onPause -> onStop -> onDestroyView
B:setUserVisibleHint(isVisibleToUser=false)
C:setUserVisibleHint(isVisibleToUser=true)
可以看出ViewPager默认只会保存两个Fragment。
当ViewPager的当前页从C换到B的时候,那么A、B、C的生命周期的调用流程为:
A: setUserVisibleHint(isVisibleToUser=false) -> onCreateView -> onActivityCreated -> onStart -> onResume
B:setUserVisibleHint(isVisibleToUser=true)
C:setUserVisibleHint(isVisibleToUser=false)
当ViewPager的当前页为C时,我们把Activity切换到后台,按下Home键,那么A、B、C的生命周期的调用流程为:
A:什么都不调用。
B:onPause -> onSaveInstanceState -> onStop
C:onPause -> onSaveInstanceState -> onStop
当Activity又切到前台后,那么A、B、C的生命周期的调用流程为:
A:什么都不调用
B:onStart -> onResume
C:onStart -> onResume
当ViewPager的当前页为C时,退出Activity那么A、B、C的生命周期的调用流程为:
A:onDestroy -> onDetach
B:onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
C:onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
使用FragmentStatePagerAdapter
FragmentStatePagerAdapter使用一个Fragment管理每个page。这个类同时也操控保存和恢复fragment的状态。
这个类适合于有大量pages的时候,比如一个列表视图。当page不可见的时候,它们的fragment也会被销毁,只会保留被保存的状态。 这种模式比FragmentPagerAdapter 使用更少的内存,但是在切换的时候会有更多的消耗。
当ViewPager的当前页从B换到C的时候,那么A、B、C的生命周期的调用流程为:
A:onSaveInstanceState -> onPause -> onStop -> onDestroyView -> onDestroy -> onDetach
B:setUserVisibleHint(isVisibleToUser=false)
C:setUserVisibleHint(isVisibleToUser=true)
可以看出,A Fragment会被remove掉,比FragmentPagerAdapter多调用了三个函数A:onSaveInstanceState 、onDestroy 和onDetach。
当ViewPager的当前页从C换到B的时候,那么A、B、C的生命周期的调用流程为:
A: setUserVisibleHint(isVisibleToUser=false) -> onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume
B:setUserVisibleHint(isVisibleToUser=true)
C:setUserVisibleHint(isVisibleToUser=false)
ViewPager的缓存
通过函数setOffscreenPageLimit(int limit)可以设置Viewpager默认帮助缓存current page前后各缓存limit个page
ViewPager动画
通过使用 ViewPager.PageTransformer 可以现在Fragment在ViewPager中的切换动画。
参考:https://developer.android.com/training/animation/screen-slide.html