本文参考了PeOS(https://www.jianshu.com/p/f14f7e9ddc00)
blueberry_mu(https://blog.csdn.net/a992036795/article/details/51790430)
菜鸟教程(https://www.runoob.com/w3cnote/android-tutorial-fragment-base.html)的博客,如有侵权,请通知删除。
在平时的开发中我们经常用到fragment,但是当你碰到面试别人问你什么是fragment以及简单介绍一下的时候,或许你会滔滔不绝的说起来,或许就会一时间语塞,不知从何说起,从哪方面说起,没错,后者就是我。今天我就梳理一下这个我们经常使用的fragment。
一、首先先从为什么要出现这个一个东西?
我们先看看它的定义:
Fragment,简称碎片,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6。
经过查阅和总结,大概都是这么一句话:
Fragment是Android 3.0(Honeycomb)被引入的。主要目的是为了给大屏幕(如平板电脑)上更加动态和灵活的UI设计提供支持。由于平板电脑的屏幕比手机的屏幕大很多,因此可用于组合和交换的UI组件的空间更大,利用Fragment实现此类设计的时,就无需管理对视图层次结构的复杂更改。
打个比方,下图的左边是平板,因为它比较宽所以可以做成左边的列表和右边的详情页面的组合,然后如果把两个东西直接写在一个activity里的话,太多又太乱,而且耦合性比较高,不方便测试,所以这时候就引入了两个fragment,他们都属于当前的一个activity,但是他们又单独写在自己的fragment,清晰又模块儿化,写着就很舒服。
对于右边的手机来说就只能写两个activity来进行跳转。因为。。。它不够宽。。。
那么既然是给平板手机用的,那为什么现在手机上用的也很多,而且还总是被别人问起呢,这背后的原因相比肯定是只有一点:方便。根据这一点那就继续研究,它为什么方便呢?肯定是因为有一些别的东西无法睥睨的地方或者特性。那么就看看它的特性吧。
- Fragment是依赖于Activity的,不能独立存在的。
- 一个Activity里可以有多个Fragment。
- 一个Fragment可以被多个Activity重用。
- Fragment有自己的生命周期,并能接收输入事件。
- 我们能在Activity运行时动态地添加或删除Fragment。
有了这些特性,再想一想手机和我们之前使用的应用,我们发现它对手机开发还是有益的。比如说:
- 模块化(Modularity):我们不必把所有代码全部写在Activity中,而是把代码写在各自的Fragment中。
- 可重用(Reusability):多个Activity可以重用一个Fragment。
- 可适配(Adaptability):根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这样用户体验更好。
二、其次我们怎么创建使用这个东西?
先贴一张生命周期图来看看
走一边生命周期:
①Activity加载Fragment的时候,依次调用下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume
②当我们弄出一个悬浮的对话框风格的Activity,或者其他,就是让Fragment所在的Activity可见,但不获得焦点 onPause
③当对话框关闭,Activity又获得了焦点: onResume
④当我们替换Fragment,并调用addToBackStack()将他添加到Back栈中 onPause -> onStop -> onDestoryView !!注意,此时的Fragment还没有被销毁哦!!!
⑤当我们按下键盘的回退键,Fragment会再次显示出来: onCreateView -> onActivityCreated -> onStart -> onResume
⑥如果我们替换后,在事务commit之前没有调用addToBackStack()方法将 Fragment添加到back栈中的话;又或者退出了Activity的话,那么Fragment将会被完全结束, Fragment会进入销毁状态 onPause -> onStop -> onDestoryView -> onDestory -> onDetach
接下来就是创建一个fragment,创建fragment有两个方式。
静态添加:通过xml的方式添加,缺点是一旦添加就不能在运行时删除。
动态添加:运行时添加,这种方式比较灵活,因此建议使用这种方式。
1.静态加载Fragment
示例代码:
Step 1:定义Fragment的布局,就是fragment显示内容的
Step 2:自定义一个Fragment类,需要继承Fragment或者他的子类,重写onCreateView()方法 在该方法中调用:inflater.inflate()方法加载Fragment的布局文件,接着返回加载的view对象
public class Fragmentone extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1, container,false);
return view;
}
}
Step 3:在需要加载Fragment的Activity对应的布局文件中添加fragment的标签, 记住,name属性是全限定类名哦,就是要包含Fragment的包名,如:
<fragment
android:id="@+id/fragment1"
android:name="com.jay.example.fragmentdemo.Fragmentone"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
Step 4: Activity在onCreate( )方法中调用setContentView()加载布局文件即可!
2.动态加载Fragment
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Display dis = getWindowManager().getDefaultDisplay();
if(dis.getWidth() > dis.getHeight())
{
Fragment1 f1 = new Fragment1();
getFragmentManager().beginTransaction().replace(R.id.LinearLayout1, f1).commit();
}
else
{
Fragment2 f2 = new Fragment2();
getFragmentManager().beginTransaction().replace(R.id.LinearLayout1, f2).commit();
}
}
}
然后就是怎么使用fragment,对于怎么使用这句话相比很难理解,换句话说就是怎么运用它来完成常见的数据传递,组建获取,以及管理一个activity中的所有fragment等等。
前两个数据传递,组件获取,直接从下图就可以了解到。
其中重点说一下fragment传递数据到activity这块儿
Step 1:定义一个回调接口:(Fragment中)
/*接口*/
public interface CallBack{
/*定义一个获取信息的方法*/
public void getResult(String result);
}
Step 2:接口回调(Fragment中)
/*接口回调*/
public void getData(CallBack callBack){
/*获取文本框的信息,当然你也可以传其他类型的参数,看需求咯*/
String msg = editText.getText().toString();
callBack.getResult(msg);
}
Step 3:使用接口回调方法读数据(Activity中)
/* 使用接口回调的方法获取数据 */
leftFragment.getData(new CallBack() {
@Override
public void getResult(String result) { /*打印信息*/
Toast.makeText(MainActivity.this, "-->>" + result, 1).show();
}
});
还有人会问了,那么两个fragment之间互传数据怎么说?
其实这很简单,找到要接受数据的fragment对象,直接调用setArguments传数据进去就可以了 通常的话是replace时,即fragment跳转的时候传数据的,那么只需要在初始化要跳转的Fragment 后调用他的setArguments方法传入数据即可!
如果是两个Fragment需要即时传数据,而非跳转的话,就需要先在Activity获得f1传过来的数据, 再传到f2了,就是以Activity为媒介~
代码示例如下:
FragmentManager fManager = getSupportFragmentManager( );
FragmentTransaction fTransaction = fManager.beginTransaction();
Fragmentthree t1 = new Fragmentthree();
Fragmenttwo t2 = new Fragmenttwo();
Bundle bundle = new Bundle();
bundle.putString("key",id);
t2.setArguments(bundle);
fTransaction.add(R.id.fragmentRoot, t2, "~~~");
fTransaction.addToBackStack(t1);
fTransaction.commit();
最后就是它的管理了,相信在上面的代码中也看到了它的管理者,下面贴张图看看:
三、源码分析
这里先搁置一下,接下来会继续补上它的内容。嘿嘿