Fragment完全解析系列(一)基础概念
来源:互联网 发布:知行学院地址 编辑:程序博客网 时间:2024/05/21 15:27
简介
Fragment俗称碎片,在Android3.0后为了提升页面展示效率被Google开发人员提出。它依附于Activity存在,它拥有自己的生命周期,也可以和用户相互。Fragment存在于Activity中,通过Activity可以实现对Fragment的动态添加、删除、灵活显示UI等操作。
Fragment生命周期
Fragment必须依赖于Activity而存在,所以它的生命周期和Activity必定是密不可分的,参考下图。
我们抽出和Activity不同的阶段来解读。
onAttach(Context)
当Fragment与Activity发生关联时调用;
onCreateView(LayoutInflater, ViewGroup, Bundle)
创建Fragment的视图;
onActivityCreated(Bundle)
当Activity的onCreate()方式执行时调用;
onDestroyView()
和onCreateView()对应,销毁Fragment视图时调用;
onDetach()
和onAttach()对应,取消与Activity的关联关系时调用;
PS
当我们重写Fragment的方法时,除了onCreateView()方法外,重写其它任何方法时都必须引用其父类方法。
Fragment静态使用
静态使用Fragment是其用法当中最简单的一种,具体的实现:
1. 新建类继承Fragment,重写onCreateView()方法来实现我们自己的布局;
2. 在xml文件中,利用”fragment”控件及其属性”name”将布局与Fragment绑定,在Activity中直接声明控件使用。
举个很简单的例子:
FragmentOne.class
FragmentTwo.class
MyActivity.class
activity_fragment.xml
Fragment动态使用
相比静态使用,动态使用更加灵活,我们可以在代码中动态的控制Fragment的显示、隐藏、删除,还实现多个Fragment动态切换等操作。了解动态使用的用法其实我们只需要了解一下几个和Fragment相关的类即可。
Fragment.class,用于定义Fragment;
FragmentManager.class,主要用于Activity操作Fragment;
FragmentTranscation.class,Fragment的事务。
1.获取FragmengManager
FragmentManager fm = getFragmentManager();
2.FragmentTranscation事务操作
//开启一个事务FragmentTransaction transaction = fm.beginTransaction();//add,添加fragment到activitytransaction.add(R.id.fragment, mFragmentOne);//remove,如果该fragment没有被添加到回退栈则实例被销毁transaction.remove(mFragmentOne);//replace,使用一个fragment替代另一个fragment,先add后removetransaction.replace(R.id.fragment, mFragmentTwo);//hide,隐藏当前的fragment视图,不销毁实例transaction.hide(mFragmentOne);//show,将当前的fragment显示出来transaction.show(mFragmentOne);//添加到回退栈,我们单独分析它transaction.addToBackStack();//commit,提交事务,熟悉事务的都应该知道,commit之后我们以上操作才会生效transaction.commit();
以上便是Fragment的动态使用相关的API,稍微练习一下,很简单。最重要的是,我们需要考虑这些api会对fragment造成什么影响,哪个销毁fragment的视图,哪个销毁fragment的实例,哪个仅仅控制fragment的可见与否。
Fragment回退栈
Activity切换时,相信大家都知道是通过栈的形式,不断压栈出栈,在Fragment的时候,如果你不是手动开启回退栈,它是直接销毁再重建,但如果将Fragment任务添加到回退栈,情况就会不一样了,它就有了类似Activity的栈管理方式。
我们将fragment的任务添加到回退栈当中去,当我们点击back键时,不会直接退出activity,而将看到上次操作的fragment。
我们可以这样理解,当activity销毁之前,会检查其管理的fragment回退栈中是否存在fragment,如果存在fragment则每按一次back键则弹出一次fragment直到回退栈里不存在fragment时activity才退出。
上面的GIF中,有一个Activity三个Fragment,
1.刚开始显示FragmentA;
2.在FragmentA中填写“111”点击跳到FragmentB;
3.在FragmentB中填写“222”点击跳到FragmentC;
4.按下back,从FragmentC返回到FragmentB,数据“222”存在;
5.按下back,从FragmentB返回到FragmentA,数据“111”不存在了;
下面对照代码来分析。
MyActivity.class
直接将FragmentOne添加到fragment布局上去,这里之所以没有调用addToBackStack()方法,是为了防止在此处back时引起的Activity白底。
FragmentOne.class
从Fragment的动态使用介绍中我们知道,调用replace()方法就是调用remove()、add(),当我们不将事务加入到回退栈时,此Fragment会被销毁。事务加入到回退栈中时只是销毁FragmentA的视图而不会销毁FragmentA的实例,所以back回来的时候存在FragmentA,但是我们输入的“111”不见了。(销毁视图但不销毁实例)。
FragmentTwo.class
我们做了两个操作,一隐藏了该Fragment,二将事务加入到回退栈,既没有销毁Fragment的视图也没有销毁Fragment的实例,所以FragmentThree按back返回时,FragmentTwo显示且其数据“222”依旧存在。
FragmentThree.class
此段代码什么也没做,可忽略。
PS
在写这个例子时,我惊讶地发现我从FragmentThree开始返回时,FragmentTwo、FragmentOne中的数据都保留了下来,FragmentOne上依然有数据“111”,后来发现是我们创建布局时,给xml中的EditText定义了id,导致自动调用了onSaveInstanceState()方法恢复了数据,才出现以上描述的状况。
Fragment懒加载
这个场景我们应用的还是很多的。比如今日头条APP,上面的标签“推荐”、“热点”、“视频”等,当我们第一次打开APP时,第一次选中标签(该标签下无数据)时自动加载数据,当下次在选中此标签时(标签已有数据)不再加载数据。
懒加载的常用场景是Fragment结合Viewpager使用,它的核心就是当Fragment可见并且未加载数据时加载数据,其它情况不再加载数据。满足两个条件,(可见、未加载数据)。可见与否我们可以通过Fragment提供的setUserVisibleHint(boolean isVisibleToUser);方法中的参数得到,即isVisibleToUser为true可见,false不可见。我们定义一个变量来表示是否加载了数据,isLoadDataFlag默认为false,当加载了数据后置为true。这些操作要保证Fragment的视图已创建的,设置一个可以判断是否创建了视图的标志,isViewCreated初始化为false,在onCreateView()中置为true。
我们通过三个标志来判定是否加载数据。
//Fragment视图是否已创建private boolean isViewCreated = false;//Fragment是否加载了数据private boolean isLoadDataSuccess = false;//Fragment是否对用户可见,此变量有api提供boolean isVisibleToUser;
由此,我们来写一个完整的懒加载LazyFragment.class
public abstract class LazyFragment extends Fragment { //Fragment视图是否已创建 private boolean isViewCreated = false; //Fragment是否加载了数据 private boolean isLoadDataSuccess = false; @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(getLayoutId(), container, false); initView(view); isViewCreated = true; return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if ( getUserVisibleHint() ){ isLoadDataSuccess = true; loadData(); } } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if ( isVisibleToUser && isViewCreated && !isLoadDataSuccess ){ isLoadDataSuccess = true; loadData(); } } public abstract int getLayoutId(); public abstract void initView(View view); public abstract void loadData();}
为什么 loadData() 会在两个地方执行?为什么 onActivityCreated 也要执行呢?因为,ViewPager 默认显示第一页,第一页肯定要先加载数据,而且 setUserVisibleHint 的执行顺序又是在 onCreatView 之前,同时 onCreatView 需要初始化界面和修改 isViewCreated 的值。所以就需要在 onActivityCreated 里执行一次。
- Fragment完全解析系列(一)基础概念
- Fragment完全解析(一)
- TCP/IP系列基础概念(一)
- java多线程系列(一)基础概念
- 【Fragment精深系列5】fragment findViewById()返回null完全解析
- 【Fragment精深系列5】fragment findViewById()返回null完全解析
- Fragment 完全解析(下)
- Fragment完全解析(上)
- Fragment完全解析(下)
- Gradle系列《一》: 基础概念
- Android Fragment完全解析,关于碎片你所需知道的一切,Fragment入门(一)
- Fragment(一)Android Fragment完全解析,关于碎片你所需知道的一切
- Fragment系列(一)
- Dubbo系列(一)Dubbo之基础概念
- Android Fragment 完全解析(下)
- Android Fragment 完全解析(上)
- Android Fragment完全解析(上)
- Android Fragment完全解析(下)
- 自定义View之CircleImageView
- DecelerateInterpolator(float factor)
- bzoj 3011: [Usaco2012 Dec]Running Away From the Barn (可并堆)
- for循环删除(ArrayList.remove)及改进方法及对象在内存中的理解
- 【Get深一度】MATLAB中对信号做 fft 后为何还要做 fftshift ?
- Fragment完全解析系列(一)基础概念
- ajax与HTML5 history pushState/replaceState实例(pjax)
- SDWebImage原理
- R文件不能自动生成的原因之一
- python面试
- H.266:模板匹配的运动矢量生成(FRUC)
- 驱动
- linux 常用命令
- UVa122 二叉树的层次遍历