Fragment的产生与介绍
Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套app,然后拷贝一份,修改布局以适应什么超级大屏的。难道无法做到一个app可以同时适应手机和平板吗?答案是,当然有,那就是Fragment。Fragment出现的初衷就是为了解决这样的问题。
你可以把Fragment当成Activity一个界面的一部分,甚至Activity的界面由完全不同的Fragment组成,更帅气的是Fragment有自己的声明周期和接收、处理用户的事件,这样就不必要在一个Activity里面写一堆事件、控件的代码了。更为重要的是,你可以动态的添加、替换、移除某个Fragment。
Fragment的生命周期
Fragment必须是依存于Activity而存在的,因此Activity的生命周期会直接影响到Fragment的生命周期。官网这张图很好的说明了俩者的关系:
Fragment的使用及管理
基础的使用这里就不在说了,主要写一下开发中遇到的问题和经验。
1.获取当前的Fragment对象。
public Fragment getCurrentFragment() { Fragment currentFragment = null; FragmentManager fragmentManager = getSupportFragmentManager(); Listfragments = fragmentManager.getFragments(); if (null != fragments) { for (Fragment tmp : fragments) { if (tmp != null && tmp.isVisible()) { currentFragment = tmp; } } } return currentFragment; }
2.当使用多个Fragment代替Activity时,需要控制返回键。因为默认情况下按返回,会退出Activity。
FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction ft = fragmentManager.beginTransaction(); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.addToBackStack(null); ft.add(R.id.frame_content, new MyFragment()); ft.commit();
重写Activity的退出方法。
@Override public void onBackPressed() { FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.popBackStack(); }
3.切换Fragment时保存数据
要想在切换Fragment时保存数据,需要防止Fragment重新实例化。
public void switchContent(Fragment from, Fragment to) { if (mContent != to) { mContent = to; FragmentTransaction transaction = mFragmentMan.beginTransaction().setCustomAnimations( android.R.anim.fade_in, R.anim.slide_out); if (!to.isAdded()) { // 先判断是否被add过 transaction.hide(from).add(R.id.content_frame, to).commit(); // 隐藏当前的fragment,add下一个到Activity中 } else { transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个 } } }
注意:当使用Fragment代替Activity时,如果使用上面第二个方法,调用FragmentManager中的popBackStack(),那么FragmentManager会从堆栽中删除上一个Fragment,造成每次都会实例化。如:有一个Activity,有两个Fragment,分别为FA和FB。进入Activity时默认显示FA,然后操作时FA调用FB。这个时候若从FB按返回键回到FA,那么FA再次调用FB时会重新实例化。
如何避免以上问题呢?我是自己写了一些方法进行堆栽管理。
private StackfragmentStack; public void switchToFragment(int fragmentId, boolean pushStack) { Fragment currentFragment = getCurrentFragment(); // 这是我自己写的一个方法,根据ID获取不同Fragment Fragment f = getFragment(fragmentId); FragmentTransaction ft = fragmentManager.beginTransaction(); if (null != currentFragment) { ft.hide(currentFragment); } if (f.isAdded()) { ft.show(f); } else { ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.addToBackStack(null); ft.add(R.id.frame_content, f); } ft.commit(); if (null == fragmentStack) { fragmentStack = new Stack (); } if (pushStack) { fragmentStack.push(fragment); } } @Override public void onBackPressed() { fragmentStack.pop(); // 从栽弹出当前页面 if (fragmentStack.isEmpty()) { finish(); } else { int fragment = fragmentStack.peek(); switchToFragment(fragment, false); } }