若是使用Android3.0如下的版本,须要引入android.support.v4的JAR包,而后Activity继承FragmentActivity,经过getSupportFragmentManager得到FragmentManager。
Android在3.0以上版本,可直接使用Activity,经过getFragmentManager得到FragmentManager。html
一. 生命周期:
onAttach(Activity):Fragment和Activity创建关联时调用。
onCreate(Bundle)
onCreateView(LayoutInflater, ViewGroup, Bundle):为Fragment加载布局时调用。
onActivityCreated(Bundle)
onStart()
onResume()
onPause()
onStop()
onDestroyView():Fragment中的布局被移除时调用。
onDestory()
onDetach():Fragment和Activity解除关联的时候调用。android
二. 两种加载方法:
静态加载Fragment:在布局文件中直接布局<fragment>
<fragment android:id="@+id/id_fragment_title"
android:name="com.test.fragment.TitleBarFragment"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
每个fragment都须要一个惟一的标识,若是activity重启,系统能够用来恢复fragment(而且你也能够用来捕获fragment来处理事务,例如移除它. 有3种方法来为一个fragment提供一个标识:
为 android:id 属性提供一个惟一ID.
为 android:tag 属性提供一个惟一字符串.
若是以上2个都没有提供, 系统使用容器view的ID.git
动态添加Fragment主要分为4步:
1.获取到FragmentManager,在Activity中能够直接经过getFragmentManager获得。
2.开启一个事务,经过调用beginTransaction方法开启。
3.向容器内加入Fragment,通常使用replace方法实现,须要传入容器的id和Fragment的实例。
4.提交事务,调用commit方法提交。github
FragmentTransaction方法:
add(int containerViewId, Fragment fragment, String tag) 往containerView中添加一个Fragment
remove() 从Activity中移除一个Fragment,若是被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁。
replace(int containerViewId, Fragment fragment, String tag) 使用Fragment替换当前的containerView,实际上就是remove()而后add()的合体
hide() 隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
show() 显示以前隐藏的Fragment
detach() 会将view从UI中移除,和remove()不一样,此时fragment的状态依然由FragmentManager维护。
attach() 重建view视图,附加到UI上并显示。
addToBackStack(String) 添加一个Fragment事务到回退栈。用户点击Back,就是Fragment回退栈不断的弹栈。
注:
将fragment从后台堆栈中弹出, 使用FragmentManager.popBackStack() (模拟用户按下BACK 命令).
使用FragmentManager.addOnBackStackChangeListener()注册一个监听后台堆栈变化的listener.shell
三. Fragment之间进行通讯:
1. 在Fragment,使用getActivity()能够获取到关联的Activity,而后再调用Activity的findViewById方法,就能够获取到和这个Activity关联的其它Fragment的视图了。app
2. 在Activity,使用getFragmentManager.findFragmentByTag()或者findFragmentById()得到任何Fragment实例。
可是以上两种方法都不提倡,由于Fragment和Activity之间耦合太紧,应采用观察者模式,设置Listener接口,在Activity中实现接口,在Fragment中调用接口函数,从而Fragment得事件就能够通知到Activity了。less
3. 经过Hander来实现消息传送,但这也是紧耦合。
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = (MainActivity) activity;
mActivity.setHandler(mHandler);
}ide
4. 使用Bundle,也是紧耦合。
在Activity中动态添加Fragment时,用Bundle封装咱们须要传递的数据。setArguments方法必须在fragment建立之后,添加给Activity前完成。
public void button(View view) {
ArgFragment arg = new ArgFragment();
Bundle bundle = new Bundle();
bundle.putString("arg", "XXX");
arg.setArguments(bundle);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.layout_fragment, arg);
ft.commit();
}
而后在ArgFragment取出Bundle对象:
Bundle bundle = getArguments();
if (bundle != null){
String str = bundle.getString("arg");
}函数
四. 若是系统内存不足或者切换横竖屏或者app长时间在后台运行,Activity均可能会被系统回收,而后Fragment并不会随着Activity的回收而被回收,从而致使,Fragment丢失对应的Activity。解决方案是:布局
1. Activity重写onSaveInstanceState方法,将super.onSaveInstanceState(outState);注释掉,让其再也不保存Fragment的状态,达到其随着Activity一块儿被回收的效果!
2. 根据savedInstanceState来区别处理:
public class MainActivity extends FragmentActivity {
private FragmentManager fragmentManager;
private AFragment aFragment;
private BFragment bFragment;
private int currentIndex = TempData.fragmentNo; //默认为0
private void getIntentData() {
boolean hasData = false;
Bundle b = getIntent().getExtras();
if( b!=null && !b.isEmpty() && b.containsKey("index") ) {
hasData = true;
int index = b.getInt("index");
currentIndex = index;
}
}
@Override
/* can be restored via {@link #onCreate} or {@link #onRestoreInstanceState}
* */
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("currentIndex", currentIndex);
UtilLog.d(TAG, "MainActivity onSaveInstanceState(): currentIndex = " + currentIndex);
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if ( savedInstanceState == null ) {
UtilLog.d(TAG, "MainActivity onRestoreInstanceState(null)");
changeFragment(currentIndex);
} else {
// 说明FragmentActivity曾经被系统回收,而Fragment多是没有被回收的,
// 须要先找回当前处于显示状态的Fragment,并找回全部没有被回收的Fragment,
// 从而避免Fragment显示重叠。
if (savedInstanceState.containsKey("currentIndex")) {
currentIndex = savedInstanceState.getInt(
"currentIndex", TempData.fragmentNo);
UtilLog.d(TAG, "MainActivity onRestoreInstanceState(savedInstanceState): currentIndex = " + currentIndex);
}
UtilLog.d(TAG, "MainActivity onRestoreInstanceState(savedInstanceState)");
showExistedFragment(currentIndex);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
UtilLog.d(TAG, "MainActivity onCreate() <--");
super.onCreate(savedInstanceState);
getIntentData();
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN |
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
if ( savedInstanceState == null ) {
UtilLog.d(TAG, "MainActivity onCreate(null)");
changeFragment(currentIndex);
} else {
// “内存重启”时调用, 此时Fragment可能还存在,须要经过Tag找回
if (savedInstanceState.containsKey("currentIndex")) {
currentIndex = savedInstanceState.getInt(
"currentIndex", TempData.fragmentNo);
UtilLog.d(TAG, "MainActivity onCreate(savedInstanceState): currentIndex = " + currentIndex);
}
UtilLog.d(TAG, "MainActivity onCreate(savedInstanceState)");
showExistedFragment(currentIndex);
}
UtilLog.d(TAG, "MainActivity onCreate() -->");
}
@Override
protected void onNewIntent(Intent intent) {
UtilLog.d(TAG, "MainActivity onNewIntent() <--");
super.onNewIntent(intent);
// must store the new intent unless getIntent() will return the old one
setIntent(intent);
if ( (Intent.FLAG_ACTIVITY_CLEAR_TOP & intent.getFlags()) != 0 ) {
getIntentData();
if( TempData.fragmentNo != currentIndex ) {
changeFragment(currentIndex);
}
}
}
private void hideFragment(FragmentTransaction fragmentTransaction) {
if (aFragment != null ) {
fragmentTransaction.hide(aFragment);
}
if (bFragment != null) {
fragmentTransaction.hide(bFragment);
}
}
private void changeFragment(int index) {
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
currentIndex = index;
TempData.fragmentNo = index;
hideFragment(fragmentTransaction);
switch (index) {
case 0:
if(aFragment!=null && aFragment.isAdded()){
fragmentTransaction.show(aFragment);
}else {
aFragment = new AFragment();
fragmentTransaction.add(R.id.details, aFragment, "AFragment");
}
break;
case 1:
if(bFragment!=null && bFragment.isAdded()){
fragmentTransaction.show(bFragment);
}else {
bFragment = new BFragment();
fragmentTransaction.add(R.id.details, bFragment, "BFragment");
}
break;
default:
break;
}
fragmentTransaction.commitAllowingStateLoss();
}
private void showExistedFragment(int index) {
Fragment first = fragmentManager.findFragmentByTag("AFragment");
if(first!=null && first instanceof AFragment) {
aFragment = (AFragment) first;
}
Fragment second = fragmentManager.findFragmentByTag("BFragment");
if(second!=null && second instanceof BFragment) {
bFragment = (BFragment) second;
}
changeFragment(index);
}
}
Fragment内存重启的模拟和处理:
adb shell pm list packages 读取到本机安装的应用列表
adb shell am kill 包名 将该应用置于后台,而后模拟该应用的内存重启
http://www.yrom.net/blog/2013/03/10/fragment-switch-not-restart/
http://www.cnblogs.com/kissazi2/p/4116456.html
五. 第三方fragmentation
// https://github.com/YoKeyword/Fragmentation
compile 'me.yokeyword:fragmentation:0.10.4'
1. 加载多个同级根Fragment,没有添加Fragment事务到回退栈。切换采用showHideFragment(...)
public class MainActivity extends SupportActivity{
@Override
/* can be restored via {@link #onCreate} or {@link #onRestoreInstanceState}
* */
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("mSelectedTabbar", mSelectedTabbar);
super.onSaveInstanceState(outState);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.zhihu_activity_main);
if (savedInstanceState == null) {
mFragments[FIRST] = ZhihuFirstFragment.newInstance();
mFragments[SECOND] = ZhihuSecondFragment.newInstance();
mFragments[THIRD] = ZhihuThirdFragment.newInstance();
mFragments[FOURTH] = ZhihuFourthFragment.newInstance();
// loadMultipleRootFragment的做用:
// 一次性加载多个Fragments,可是containerId只默认显示其中一个,
// 默认显示的那个Fragment会依次调用onCreateView(),onLazyInitView()
// 其余被隐藏的Fragment会依次调用onHiddenChanged(true),onCreateView()
loadMultipleRootFragment(R.id.fl_container, FIRST,
mFragments[FIRST],
mFragments[SECOND],
mFragments[THIRD],
mFragments[FOURTH]);
} else {
// 这里库已经作了Fragment恢复,全部不须要额外的处理了, 不会出现重叠问题
// 这里咱们须要拿到mFragments的引用,也能够经过getSupportFragmentManager.getFragments()自行进行判断查找(效率更高些),用下面的方法查找更方便些
mFragments[FIRST] = findFragment(ZhihuFirstFragment.class);
mFragments[SECOND] = findFragment(ZhihuSecondFragment.class);
mFragments[THIRD] = findFragment(ZhihuThirdFragment.class);
mFragments[FOURTH] = findFragment(ZhihuFourthFragment.class);
if ( savedInstanceState.containsKey("mSelectedTabbar") ) {
mSelectedTabbar = savedInstanceState.getInt("mSelectedTabbar", FIRST);
}
}
initView();
}
public void onTabSelected(int position, int prePosition) {
mSelectedTabbar = position;
// 在作Fragment的切换时,showHideFragment的做用:
// 待显示的Fragment若是没有加载过界面,会先调用onLazyInitView(),而后调用onHiddenChanged(false)
// 待隐藏的Fragment调用onHiddenChanged(true)
showHideFragment(mFragments[position], mFragments[prePosition]);
}
}
public class NewFeatureFragment extends SupportFragment {
@Override
public void onLazyInitView(@Nullable Bundle savedInstanceState) {
super.onLazyInitView(savedInstanceState);
// 懒加载
// 同级Fragment场景、ViewPager场景均适用
}
@Override
public void onSupportVisible() {
super.onSupportVisible();
// 当对用户可见时 回调
// 无论是 父Fragment仍是子Fragment 都有效!
}
@Override
public void onSupportInvisible() {
super.onSupportInvisible();
// 当对用户不可见时 回调
// 无论是 父Fragment仍是子Fragment 都有效!
}
}
2. loadRootFragment(int containerId, SupportFragment toFragment)
加载根Fragment,将Fragment事务添加到回退栈中,是栈底元素。
3. replaceLoadRootFragment(int containerId, SupportFragment toFragment, boolean addToBack)
以replace方式加载根Fragment, 由addToBack参数决定是否将Fragment事务添加到回退栈。
public class MainActivity extends SupportActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
// 加载根Fragment,这里是将HomeFragment事务添加到回退栈中,是栈底元素
loadRootFragment(R.id.fl_container, HomeFragment.newInstance());
}
}
// 无论切换多少项,内存中始终只保留根Fragment(HomeFragment)和可见的Fragment。
public void changeContainer( int id ) {
final SupportFragment topFragment = getTopFragment(); // 获取根Fragment
if (id == R.id.nav_home) { HomeFragment fragment = findFragment(HomeFragment.class); Bundle newBundle = new Bundle(); newBundle.putString("from", "主页-->来自:" + topFragment.getClass().getSimpleName()); fragment.putNewBundle(newBundle); start(fragment, SupportFragment.SINGLETASK); } else if (id == R.id.nav_discover) { DiscoverFragment fragment = findFragment(DiscoverFragment.class); if (fragment == null) { // 将栈中的Fragment出栈直到HomeFragment为止, // 出栈的Fragment会被析构掉,出栈完成后,启动DiscoverFragment并入栈. popTo(HomeFragment.class, false, new Runnable() { @Override public void run() { start(DiscoverFragment.newInstance()); } }); } else { // 若是已经在栈内,则以SingleTask模式start,也能够用popTo start(fragment, SupportFragment.SINGLETASK); } } else if (id == R.id.nav_msg) { ShopFragment fragment = findFragment(ShopFragment.class); if (fragment == null) { popTo(HomeFragment.class, false, new Runnable() { @Override public void run() { start(ShopFragment.newInstance()); } }); } else { // 若是已经在栈内,则以SingleTask模式start,也能够用popTo popTo(ShopFragment.class, false); } } } }