[android](学习笔记1)利用activity托管fragment的基本方法
activity托管fragment,需要做到以下两点:
1. 在布局中为fragment视图安排位置;
2. 管理fragment实例的生命周期。
fragment的生命周期:
参考:http://www.cnblogs.com/purediy/p/3276545.html
fragment在代表activity工作,其生命周期状态反应了activity的生命周期状态。fragment生命周期和activity生命周期的关键区别是:fragment的生命周期方法是由托管activity而不是操作系统调用的。fragment的使用时activity自己内部的事情。
activity作为容器托管内部的fragment,使用代码来灵活添加fragment是一个不错的选择。下面给出一般步骤:
1. 定义activity1的布局文件(文件名activity1.xml),主要用于为即将要添加的fragment1安排位置
activity1.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:id="@+id/fragmentContainer"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 />
第3行为该FrameLayout添加id号,方便后续使用。这个FrameLayout就是fragment1的出现位置。注意,这个布局文件不局限于某一个fragment类的对象,它只描述了一个容器的基本信息。
2. 创建UI fragment
创建UI fragment的步骤与创建一个activity的步骤相同:
- 定义布局文件,组装界面;
- 创建fragment1类并设置其视图布局为上一步中定义的局部;
- 使用代码的方式,连接布局文件中生成的组件。
下面详细描述一下每一步的若干细节。
(1) 定义fragment1的布局(fragment1.xml) :
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 android:orientation="vertical" >
6
7 <TextView
8 android:layout_width="match_parent"
9 android:layout_height="wrap_content"
10 android:text="@string/crime_title_label"
11 style="?android:listSeparatorTextViewStyle"/>
12 <EditText
13 android:id="@+id/crime_title"
14 android:layout_width="match_parent"
15 android:layout_height="wrap_content"
16 android:layout_marginLeft="16dp"
17 android:layout_marginRight="16dp"
18 android:hint="@string/crime_title_hint"
19 />
20 <TextView
21 android:layout_width="match_parent"
22 android:layout_height="wrap_content"
23 android:text="@string/crime_details_label"
24 style="?android:listSeparatorTextViewStyle"/>
25 <Button
26 android:id="@+id/crime_date"
27 android:layout_width="match_parent"
28 android:layout_height="wrap_content"
29 android:layout_marginLeft="16dp"
30 android:layout_marginRight="16dp"
31 />
32 <CheckBox
33 android:id="@+id/crime_solved"
34 android:layout_width="match_parent"
35 android:layout_height="wrap_content"
36 android:layout_marginLeft="16dp"
37 android:layout_marginRight="16dp"
38 android:text="@string/crime_solved_label"
39 />
40 </LinearLayout>
代码中包含的字符串资源认为已经默认添加到res/values/strings.xml中
(2) 创建fragment1类,并使用fragment1.xml定义的布局:
1 public class fragment1 extends Fragment {
2 @Override
3 public void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 }
6 }
注意,在fragment1的类定义中,并没有在onCreate方法中生成fragment1的视图。我们将在另一个fragment生命周期方法中完成创建和配置fragment1的视图:
public View onCreateView(LayoutInflater inflater, ViewGroup parent,Bundle savedInstanceState)
利用该方法,将LayoutInflater创建的fragment1的视图对象返回给托管activity1。
定义类fragment1的代码更新为:
1 public class fragment1 extends Fragment {
2 @Override
3 public void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 }
6
7 @Override
8 public View onCreateView(LayoutInflater inflater, ViewGroup parent,Bundle savedInstanceState) {
9 View v = inflater.inflate(R.layout.fragment1, parent, false);
10 }
11 }
根据fragment的生命周期描述的那样,onCreateView方法是在onCreate调用之后被调用的。注意第9行代码,通过调用LayoutInflater.inflate方法生成的fragment1的视图,传入的是fragment1的布局资源ID。为了自行通过代码添加fragment1的视图给父视图,这里第三个参数选择false。
(3) 使用代码的方式,连接布局文件中生成的组件:
创建的视图对象v中还定义了一系列的控件(参见fragment1.xml的定义),可以通过View.findViewById得到它们。
3. 添加fragment到activity
向托管activity1中添加fragment1,需要使用FragmentManager,它负责具体管理fragment队列和fragment事务的回退栈。
为了得到托管activity1的fragment管理器,可以在它的onCreate方法中添加getFragmentManager方法的调用:
1 public class activity1 extends FragmentActivity {
2 @Override
3 public void onCreate(Bundle savedInstanceState) {
4 super.onCreate(savedInstanceState);
5 setContentView(R.layout.activity1);
6
7 FragmentManager fm = getFragmentManager();// <-- NEW CODE
8 }
9 }
添加fragment1实例到activity1,其实是在向FragmentManager提交一个新的Fragment事务(Add事务),先看代码:
public class activity1 extends FragmentActivity {
protected abstract Fragment createFragment();
@Override
protected void onCreate(Bundle savedInstanceState) {
// step1
super.onCreate(savedInstanceState);
setContentView(R.layout.activity1);
FragmentManager fm = getFragmentManager();
// using container view resource to apply a fragment from FragmentManager. <resource ID <--> fragment>
/*
* FragmentManager管理一个fragment队列,容器视图资源可以与一个特定的fragment绑定。
* 程序试图在当前FragmentManager管理的fragment队列中查找与资源ID(R.id.fragmentContainer)绑定的fragment,
* 如果找到了就直接返回该fragment,否则就提交一个添加新fragment到队列的事务,提交前绑定新fragment和指定
* 资源(R.id.fragmentContainer)。这段代码的实际作用,就是保证与R.id.fragmentContainer绑定的fragment存在于
* 当前FragmentManager管理的fragment队列中。
* 当添加fragment的事务提交之后,该fragment的生命周期方法onCreate方法和onCreateView方法才依次被调用,
* FragmentManager负责调用队列中fragment的生命周期方法。
*/
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = createFragment();
// step2
fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
}
}
}
代码中已经添加了比较详细的注释,大致意思是先利用资源ID(R.id.fragmentContainer)找与之对应的fragment(想要找到fragment1的实例),如果当前fragment队列中没有匹配的,就提交一个add事务,add一个与资源ID(R.id.fragmentContainer)对应的fragment(fragment1的新实例)。这个资源ID就是一开始提到的fragment1对应的容器(即FrameLayout)的ID。
归纳一下:
activity1的布局对应R.layout.activity1
fragment1的实例对象对应R.id.fragmentcontainer,也从侧面说明,fragment1的实例只是托管activity1的一个组件
fragment1中视图v的布局对应R.layout.fragment1
另外,FragmentManager所管理的fragment队列中有可能已经存在了fragment1的实例(要不然为什么首先通过ID号去find一把),为什么?试想一下,如果activity1因为设备旋转或内存回收而被销毁后再重建,整个过程中,原本存在于activity1中的整个fragment队列都会被保存,自然包括fragment1的实例。activity1在重建时会调用onCreate方法,新的FragmentManager首先获取之前保存的fragment队列,方便地回复之前的状态,fragment1的旧有实例自然已经存在了。
历经三步,fragment1实例成功交由activity1托管(即成功添加到activity1)。
下一篇:主要总结一下界面布局相关的知识。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。