Android学习笔记(一): Fragment(一) 基本概念和生命周期
为何引入Fragment
我们之前的Activity都是都是全屏处理较为简单的单一事务功能,适合于屏幕尺寸较小的智能手机,但是对于平板,有更大的显示空间,运行用户在上面处理更多的功能,例如屏幕左边是email列表,右边的某email的内容。于是在Android 3.0引入了fragment。Fragment不仅可用于平板,同样也可用于手机尺寸.
大小屏幕的适配
某种意义上Fragment是屏幕中的一个子activity,但是在一个屏幕显示多个activity会造成概念和逻辑的混乱,所以引入fragment的概念,可以理解为屏幕中的一块UI,可作为activity的一部分。Fragment是view的容器,加载layout,处理一小部分屏幕,它是activity的一部分。Fragment提供的UI和代码的重用,例如,在大屏幕设备中,显示左右两个fragment或者上下两个fragment(具体看orientation),在小屏幕设备中则显示其中一个fragment。
使用fragment,将很容易处理这种情况,activity只需要对fragment进行布局,具体的view的摆放和操作,由fragment进行处理。
横屏、竖屏切换
当屏幕进行横屏/竖屏的切换(模拟器转向可以简单按数字小键盘的“7”),activity会退出,从代码中看调用了onDestroy(),重新加载activity(调用了onCreate()),我们需要对原有状态保存,以便切换屏幕后,用户能继续操作,而不是重头开始。保存数据或状态会比较麻烦,可以用fragment来解决。
返回键
按返回键,activity同样也会调用onDestroy()退出。如果在应用中,再次进入该activity,有时也会希望在上次基础上继续执行,同样也存在状态保持的问题。fragment中,按返回键,根据fragment stack进行回退,仍然留在当前的activity中。
activity切换屏幕或者退出,是重头再来,对原有数据的保存会比较麻烦.
fragment,如该按返回键,会根据fragment stack进行回退,但仍然留在当前的activity中.
什么是Fragment
Activity是Context的继承,而fragment是Object的继承,在android.app包中。fragment可具有层次结构的view(来自xml或者代码)。Fragment有一个bundle可以存贮数据,和activity类似,在创建时进行初始化调用,此外还有一个bundle用于保存现有状态,在onCreate(),onInflate(),onCreateView() 和onActivityCreated()都指向该对象。
一个activity可以显示多个fragment,如果fragment A被fragment B替代,则fragment A会被放入back stack中,用户按返回键时,可以重新显示fragment A。
一个fragment具有一个tag和一个ID,可用于索引
fragment的生命周期如下。这个图先放在这里,以后结合小例子理解。
小例子:
小例子运行效果
这是一个书名和书简介的例子。运行如下图。Activity由左右两个Fragment组成,左边显示书名列表,右边显示书的简介。用户点击左边的书名,右边fragment则自动显示该书的简介。
其实就两个Fragment在一个Acitivity中.
Acitivity的布局可以为: 在布局中就有 Fragment 和 FrameLayout, Fragment对应的路径是Fragment类,所以说Activity只需要设置布局就行了.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <!-- 设置左边Fragment的id,并直接通过class属性给出该fragement对应的类为TitleFragment,需要注意fragment并不是view,不支持里面子tag,即不支持<fragment …. ><…></fragment>的格式 --> <fragment class="com.wei.flowingflying.pro.ProFragment.TitleFragment" android:id="@+id/titles" android:layout_weight="1" android:layout_width="0px" android:layout_height="match_parent" /> <!-- 注意:这是FrameLayout,不是fragment,是view,右边fragment的呈现有左边fragment的操作决定,不指定对应的类,可以由不同的类来具体实现UI --> <FrameLayout android:id="@+id/details" android:layout_weight="2" android:layout_width="0px" android:layout_height="match_parent" /> </LinearLayout>
实现Fragment指定调用类TitleFragment
Fragment可有一个view hierarchy(视图对象),以之与用户互动。这个view层级可以根据XML布局文件被创建(inflated)或通过代码创建。view层级需要与activity关联,才能被用户看见。Fragment的最初的两个生命周期为onInflate和onAttach
1.onInflate() 被创建
首先调用:在Activity调用setContentView()时,xml中有<fragment>时被调用。bundle存贮的是fragment的状态,并非初始化的值。一般而言,此时太早,还没有和activity关联,一般很少需要在此进行处理,除非我们需要处理fragment的属性或参数。在API的reference中,Fragment的主要lifecycle甚至没有将onInflate()列入,因此在实际编程中,会较少用到。
2.onAttach() :
fragment 与 activity 关联后调用// 在其他方法中实现需要获取activity对象,getActivity()
@Override //【2】在fragment与activity关联后调用onAttach()。由于右边fragment的具体实现在activity的showDetails()中实现,需要获取activity的对象。 当然也可以直接用getActivity()获取。 public void onAttach(Activity activity) { showInfo("onAttach() is called. activity is " + activity); showInfo(" getActivity() : " + getActivity()); super.onAttach(activity); myActivity = (FragmentBasicTest)activity; }
调用:activity调用setContentView时,先调用Flagment中的onflate(),然后调用onAttach()。在onInfalte()中可以读取到我们setContentView里面的布局xml文件
<fragment… >设置的属性。如果布局文件中<fragment …>中并没有指定class属性,而是在代码中实现,故没有onInflate()状态。
与activity的关联:看到onInfalte()和onAttach()都可以获得activity对象,但是如果采用getActivity()来获取,则发现onInfalte()的阶段对处理UI太早,都不能关联到activity。
参数:在整个生命周期,可以通过getArguments()来获取参数,但是不能在与activity关联后进行setArgments(),只能在初始化极早的阶段,例如构造函数和onInflate()。
3.onCreate()和onCreateView()
@Override
//【3】在创建fragment中进行初始化时调用。注意此处的bundle参数,是存储fragment的状态。[如果我们要为fragment启动一个后台线程,可以考虑将代码放于此处。??how] public void onCreate(Bundle savedInstanceState) { showInfo("onCreate() is called. "); super.onCreate(savedInstanceState); } @Override //【4】创建fragment,并返回fragment的view层次结构,用于对UI的设计。本例继承了ListFragment实现,由其生成ListView,它的资源ID是android.R.id.list1,或者可以通过getListView()来获取。我们在此不需要在进行特别的处理,仅用于跟踪生命周期。 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { showInfo("onCreateView() is called. "); return super.onCreateView(inflater, container, savedInstanceState); }
onCreate()和onCreateView()都是在activity调用setContentView()时被调用。也就是activity上未完成onCreate(),因此不应该在此加入与activity的view相关的代码。而后面的生命周期这是在activity完成onCreate()之后调用的。
onCreate(): 用于初始化 Fragment (有Bundle可以传递参数)
onCreateView():(创建Fragment ,并返回fragment的view层次结构,用于UI设计)
onActivityCreated()
onActivityCreated顾名思义,是在activity完成onCreate()后被调用。我们可以在此处理activity的其他UI操作,而其他的fragment已经与activity关联,我们可以进行相互间处理。这也是用户看到UI界面之前的最后一个状态,对于从saved状态中重新创建activity及fragment来讲是重要状态。
回想一下,在ListActivity中是在setContentView()后面进行Adapter的设置,因为setContentView已经提供了view层级,因此在fragment中具体设置list也放在fragment的onCreateView()之后的生命周期onActivityCreated()中执行。
@Override //【5】onActivityCreated()在activity完成onCreate()后执行,在此可以加入UI设计(onCreateView())之后,UI被用户看到之前的代码。 public void onActivityCreated(Bundle savedInstanceState) { showInfo("onActivityCreated() is called."); super.onActivityCreated(savedInstanceState); // 1)通过Adapter进行view和data的关联 setListAdapter(new ArrayAdapter<String>(getActivity(), //注意:在ListFragment中不要直接和ListView(通过id或者getListView()获取)关联,而要用setListAdapter() android.R.layout.simple_list_item_1, BooksInfo.TITLES)); ListView lv = getListView(); lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); lv.setSelection(mCurCheckPosition); //2)根据书名设置右边framgent UI。 myActivity.showDetails(mCurCheckPosition); }
onStart()、onResume()、onPause()和onStop()
这几个状态和activty的相应状体相似,对应为可视,可互动,不可互动和不可视。和activity的生命周期图相对比,从不可视的后台回复到可视的前台的过程是onStop()—>onRestart()—>onStart()。而fragment为onStop()—>onStart()。
onDestroyView()、onDestroy和onDetach()
当fragment允许与view相关的资源释放时调用onDestroyView(),清空通过onCreateView()所返回的view。接着,onDestroy()进行最后fragment状态的清空。最后调用onDetach(),删除与activity的关联()。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。