Fragment
碎片(Fragment)是一种可以嵌入在活动(Activity)中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间。Fragment拥有自己的生命周期,可以接受处理用户的事件,并且可以在一个Activity中动态的添加、替换、移除不同的Fragment,对于信息的展示具有很大的便利性。
Fragment的生命周期
Fragment是依附于Activity存在的,因此它的生命周期收到Activity的生命周期影响。
Fragment比Activity多了几个生命周期的回调方法:
1 . onAttach(Activity):当Fragment与Activity发生关联的时候调用;
2 . onCreateView(LayoutInflater,ViewGroup,Bundle):创建该Fragment的视图;
3 . onActivityCreated(Bundle):当Activity的onCreate()方法返回时调用;
4 . onDestroyView():与onCreateView(LayoutInflater,ViewGroup,Bundle)方法对应,当该Fragment的视图被移除时调用;
5 . onDetach():与onAttach(Activity)方法对应,当Fragment与Activity取消关联时调用;
注意:除了onCreateView()方法,其他的所有方法如果重写了,必须调用父类对于该方法的实现。
Fragment基础用法
有两个不同包下面的Fragment都可以使用,一个是系统内置的android.app.Fragment,一个是support-v4库中的android.support.v4.app.Fragment。建议使用support-v4库中的Fragment,因为可以让碎片在所有Android系统版本中保持功能一致性。比如说在Fragment中嵌套使用Fragment,这个功能是在Android4.2系统中才开始支持的,如果你使用的是系统内置的Fragment,那么在4.2系统之前的设备运行你的程序就会崩溃,而使用support-v4库中的Fragment就不会出现这个问题。
另外,我们不需要在build.gradle文件中添加support-v4库的依赖,因为build.gradle文件中已经添加了appcompat-v7库的依赖,而这个库会将support-v4库也一起引入进来。
使用Android Studio的高版本,会默认使用androidx下面的Fragment,不提供使用support-v4包下面的Fragment。
静态添加Fragment
静态添加Fragment比较简单,创建要显示的Fragment,然后在Activity的xml布局中添加<fragment>标签,需要使用属性name来添加要展示的Fragment,name属性值为要显示的Fragment的路径。然后就可以在Activity中显示了。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".fragment.FragmentActivity">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.kang.fragment.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.kang.fragment.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
</LinearLayout>
动态添加Fragment
有时候,我们的业务逻辑会需要替换Fragment来进行动态展示,所以就需要用到动态添加Fragment。动态添加Fragment要稍微复杂一些,步骤如下:
1 . 创建要显示的Fragment,也就是进行实例化;
2 . 在v4包中,获取FragmentManager是直接通过调用getSupportFragmentManager(),使用FragmentManager对Fragment进行管理;
3 . 通过调用FragmentManager对象的beginTransaction()方法创建一个FragmentTransaction事务对象;
4 . 向布局容器内添加或替换Fragment,一般使用replace()方法实现,需要传入布局容器的id和待添加的Fragment;
5 . 提交事务,调用commit()方法来完成;
FragmentTransaction主要有以下几种方法:
1 . add():向Activity中添加一个Fragment;
2 . remove():从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁;
3 . replace():使用另一个Fragment替换当前的,实际上就是remove()和add()的合体;
4 . hide():隐藏当前的Fragment,仅仅是设为不可见,并不会销毁;
5 . show():显示之前隐藏的Fragment;
6 . detach():会将view从UI中移除,和remove()不同,此时Fragment的状态依然由FragmentManager维护;
7 . attach():重建view视图,附加到UI上并显示;
8 . commit():提交事务;
注意:在add()、replace()、hide()、show()以后都要使用commit()方法,效果才会在屏幕上显示出来;
//在Activity的xml布局中;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".fragment.FragmentActivity">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.kang.fragment.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<FrameLayout
android:id="@+id/fragment_fl"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
</LinearLayout>
//在Activity中调用;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
replaceFragment(new RightFragment());
}
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//R.id.fragment_fl就是要显示的Fragment的布局容器的id;
fragmentTransaction.replace(R.id.fragment_fl,fragment);
fragmentTransaction.commit();
}
在Fragment中模拟返回栈
当我们动态添加Fragment之后,这时按下手机的返回键,Activity就会直接退出。如果我们想要模仿Activity的返回栈的效果,按下手机的返回键回到上一个动态添加的Fragment,只需要使用FragmentTransaction的一个addToBackStack()方法。
我们在提交事务之前调用FragmentTransaction的addToBackStack()方法,这个方法接收一个名字用于描述返回栈的状态,一般传入null即可。
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//R.id.fragment_fl就是要显示的Fragment的布局容器的id;
fragmentTransaction.replace(R.id.fragment_fl,fragment);
//实现返回栈模式;
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
Fragment和Activity以及Fragment和Fragment之间的通信
- Fragment和Activity之间的通信
1 . 虽然Fragment是嵌入Activity之中显示的,但是Fragment和Activity都是各自存在于一个独立的类当中的,它们之间没有明显的方式来直接进行通信。
为了方便Fragment和Activity之间进行通信,FragmentManager提供了一个类似于findViewById()的方法,也就是findFragmentById()方法,还有一个findFragmentByTag()方法,都可以用于获取Fragment的实例。这样就可以在Activity中获取相应的Fragment的实例,就能调用Fragment中的方法了;
RightFragment rightFragment = (RightFragment)getSupportFragmentManager().findFragmentById(R.id.right_fragment);
2 . 在每个Fragment中都可以通过调用getActivity()方法来得到和当前Fragment相关联的Activity实例。有了Activity实例以后,就可以调用Activity之中的方法了;
FragmentActivity fragmentActivity = (FragmentActivity)getActivity();
3 . 如果Activity中包含自己管理的Fragment的引用,可以通过引用直接访问所有的Fragment的public方法;
Fragment和Fragment之间的通信
在一个Fragment之中可以获取到与它相关联的Activity,然后再通过这个Activity去获取另一个Fragment的实例,这样就哭可以实现不同Fragment之间的通信了。Fragment和Activity之间的通信的优化
虽然Fragment和Activity可以通过getActivity()与findFragmentByTag()、findFragmentById()方法,进行通信。但是不提倡使用这样的操作。因为Activity担任的是Fragment间类似总线一样的角色,应当由它决定Fragment如何操作。另外,虽然Fragment不能响应Intent操作,但是Activity可以响应Intent操作,然后根据Intent的数据参数来判断显示哪个Fragment。
此处要看看使用接口来实现Activity与Fragment通信的方式
处理运行时配置发生变化
当屏幕旋转时,Activity会对屏幕上的视图进行重新绘制,因为Activity发生了重新启动,默认的Activity中的Fragment也会跟着Activity重新创建。不断的旋转自然就会不断地绘制,这是一种很耗费内存资源的操作。当旋转发生的时候,Activity会执行onCreate()方法,就会再次实例化一个新的Fragment。
我们通过检查onCreate()方法中的参数savedInstanceState可以判断,当前是否发生了Activity的重新创建。所以,我们只需要简单地判断在savedInstanceState == null的时候,才进行创建Fragment实例就可以了。
当需要重新绘制时,在onSaveInstanceState()方法中对数据进行保存,然后在onCreate()或者onCreateView()以及onActivityCreated()方法中都可以进行恢复。
Fragment的动态加载布局技巧
Fragment懒加载
-
-
-
-
-
-
-
-
-
-
-
-
-
-
---------------------last line for now--------------------