Fragment,俗称碎片,自Android 3.0开始被引进并大量使用。作为Activity界面的一部分,Fragment的存在必须依附于Activity,并且与Activity一样,拥有自己的生命周期,同时处理用户的交互动作。同一个Activity可以有一个或多个Fragment作为界面内容,并且可以动态添加、删除Fragment,灵活控制UI内容,也可以用来解决部分屏幕适配问题。
首先Fragment的使用次数是不输于其他四大组件的,而且Fragment有自己的生命周期,比Activity更加节省内存,切换模式也更加舒适,使用频率不低于四大组件。
-
静态加载
- 创建Fragment的xml布局文件
- 在Fragment的onCreateView中inflate布局,返回
- 在Activity的布局文件中的适当位置添加fragment标签,指定name为Fragment的完整类名(这时候Activity中可以直接通过findViewById找到Fragment中的控件)
-
动态加载(需要用到事务操作,常用)
- 创建Fragment的xml布局文件
- 在Fragment的onCreateView中inflate布局,返回
@Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.activity_main, container, false); }
- 初始化Fragment
- 进行add()/remove()/replace()/attach()/detach()/hide()/addToBackStack()事务操作(都是对Fragment的栈进行操作,其中add()指定的tag参数可以方便以后通过findFragmentByTag()找到这个Fragment)
- 提交事务:commit() 示例代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getSupportFragmentManager().beginTransaction() .add(R.id.fragment_container, new TestFragment(), "test") .commit(); TestFragment f = (TestFragment) getSupportFragmentManager().findFragmentByTag("test"); }
-
通过findFragmentByTag或者getActivity获得对方的引用(强转)之后,再相互调用对方的public方法。
优点:简单粗暴 缺点:引入了“强转”的丑陋代码,另外两个类之间各自持有对方的强引用,耦合较大,容易造成内存泄漏
-
通过Bundle的方法进行传值,在添加Fragment的时候进行通信
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Fragment fragment = new TestFragment(); Bundle bundle = new Bundle(); bundle.putString("key", "value"); //Activity中对fragment设置一些参数 fragment.setArguments(bundle); getSupportFragmentManager().beginTransaction() .add(R.id.fragment_container, fragment, "test") .commit(); }
优点:简单粗暴 缺点:只能在Fragment添加到Activity的时候才能使用,属于单向通信
-
利用eventbus进行通信
优点:实时性高,双向通信,Activity与Fragment之间可以完全解耦 缺点:反射影响性能,无法获取返回数据,EventBUS难以维护
-
利用接口回调进行通信(Google官方推荐)
//MainActivity实现MainFragment开放的接口 public class MainActivity extends FragmentActivity implements FragmentListener { @override public void toH5Page() { //...其他处理代码省略 } } //Fragment的实现 public class MainFragment extends Fragment { //接口的实例,在onAttach Activity的时候进行设置 public FragmentListener mListener; //MainFragment开放的接口 public static interface FragmentListener { //跳到h5页面 void toH5Page(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); //对传递进来的Activity进行接口转换 if (activity instance FragmentListener){ mListener = ((FragmentListener) activity); } } // ...其他处理代码省略 }
优点:既能达到复用,又能达到很好的可维护性,并且性能得到保证
缺点:假如项目很大了,Activity与Fragment的数量也会增加,这时候为每对Activity与Fragment交互定义交互接口就是一个很麻烦的问题(包括为接口的命名,新定义的接口相应的Activity还得实现,相应的Fragment还得进行强制转换)
-
通过Handler进行通信(其实就是把接口的方式改为Handler)
优点:既能达到复用,又能达到很好的可维护性,并且性能得到保证 缺点:Fragment对具体的Activity存在耦合,不利于Fragment复用和维护,没法获取Activity的返回数据
-
通过广播/本地广播进行通信
优点:简单粗暴 缺点:大材小用,存在性能损耗,传播数据必须实现序列化接口
-
父子Fragment之间通信,可以使用getParentFragment()/getChildFragmentManager()的方式进行
-
FragmentPageAdapter在每次切换页面的时候,是将Fragment进行分离,适合页面较少的Fragment使用以保存一些内存,对系统内存不会多大影响
@Override public void destroyItem(ViewGroup container, int position, Object object) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object + " v=" + ((Fragment)object).getView()); //FragmentPageAdapter在destroyItem的时候调用detach mCurTransaction.detach((Fragment)object); }
-
FragmentPageStateAdapter在每次切换页面的时候,是将Fragment进行回收,适合页面较多的Fragment使用,这样就不会消耗更多的内存
@Override public void destroyItem(ViewGroup container, int position, Object object) { Fragment fragment = (Fragment) object; if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + ((Fragment)object).getView()); while (mSavedState.size() <= position) { mSavedState.add(null); } mSavedState.set(position, fragment.isAdded() ? mFragmentManager.saveFragmentInstanceState(fragment) : null); mFragments.set(position, null); //FragmentPageStateAdapter在destroyItem的时候调用remove mCurTransaction.remove(fragment); }