Fragment是随着Android 3.0推出时携带的一部分,若是在1.6版本中使用,必须引入相应的支持包。Fragment最大的优点是你可以根据不同设备的屏幕大小创建动态的UI。Fragment有以下几个特点。
- 每个Fragment是个独立的模块
- 与其所在的Activity紧密的联系在一起
- 多个Activity可以共用一个Activity
1.Fragment生命周期。
首先来看下Fragment的生命周期,Fragment的生命周期和他所在的Activity的生命周期紧密联系在一起。因此看下Fragment的生命周期对理解Fragment是很有必要的。Fragment的生命周期可以用一张图来表示。
从图中可以看出Fragment的生命周期和Activity的生命周期相似,只不过是多了几个状态而已。其中从onDestroyView返回到onCreateView是需要在commit方法之前调用addToBackStack当中。
2.Fragment的创建和使用。
常用使用Fragment的方式有两种。
方法1:在Actvity的layout布局中嵌入fragment标签,该fragment必须要有android:id,否则编译会报错。
方法2:在Activity的layout布局当中可以先添加FrameLayout的view,然后再代码中动态添加Fragment。
注:在使用Fragment时,若通过Activity的支持包使用Fragment,则必须使Activity继承自FragmentActivity。即在引用Fragment的相关的类时,要确保他们来自相同的包。虽然Android本地包和Fragment支持包都有Fragment相关的类,但是不能互用。
下面来看两个示例。
示例(方法1):通过在layout中使用fragment来添加Fragment。
首先,在创建一个fragment的布局文件fragment_firts.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 <TextView 6 android:layout_width="match_parent" 7 android:layout_height="wrap_content" 8 android:textSize="20dp" 9 android:text="This is FIRST fragment"/> 10 11 </LinearLayout>
其次,创建一个MyFirstFragment继承自Fragment(这里使用的是Android包中的fragment,即android.app.Fragment),并使用上述布局。代码也很简单。
1 public class MyFirstFragment extends Fragment { 2 @Nullable 3 @Override 4 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 5 6 return inflater.inflate(R.layout.fragment_first,container,false); 7 } 8 }
最后,在MyActivity的layout中使用fragment标签引用MyFirstFragment。
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 <TextView 6 android:layout_width="match_parent" 7 android:layout_height="wrap_content" 8 android:text="MyActivity" 9 android:textSize="20dp"/> 10 <fragment 11 android:id="@+id/first_fragment" 12 android:name="com.example.zhouy.androidexercise.MyFirstFragment" 13 android:layout_width="match_parent" 14 android:layout_height="match_parent" /> 15 </LinearLayout>
运行下看结果如下。
在利用动态方式添加Fragment之前,我们先了解下fragment在代码中添加 删除和替换的方式
不管是添加、删除和替换fragment,都需要经历的步骤是
a.在Actvity中利用getFragmentManager()获取Fragment管理类FragmentManager
b.利用FragmentManager获取Transaction
c.通过Transaction来实现对Fragment的动态添加、删除和替换。
d.Transaction通过commit方法完成对Fragment的操作
这几个步骤将在利用方式2动态添加时使用,具体使用方法见示例2
示例(方式2):通过预留的View添加Fragment,通常使用FrameLayout来作为Fragment的容器。
首先,再次创建一个MySecondFragment,布局和MyFirstFragment相似,不再赘述。
其次,修改activity_my.xml的标签,添加几个按钮即添加、删除、替换,Fragment加入栈中,修改后的xml如下。
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 <TextView 6 android:layout_width="match_parent" 7 android:layout_height="wrap_content" 8 android:text="MyActivity" 9 android:textSize="20dp"/> 10 <Button 11 android:id="@+id/add_by_framelayout" 12 android:layout_width="match_parent" 13 android:layout_height="wrap_content" 14 android:textSize="20dp" 15 android:text="Framelayout添加"/> 16 <Button 17 android:id="@+id/remove_by_framelayout" 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content" 20 android:textSize="20dp" 21 android:text="删除"/> 22 <Button 23 android:id="@+id/replace_by_framelayout" 24 android:layout_width="match_parent" 25 android:layout_height="wrap_content" 26 android:textSize="20dp" 27 android:text="替换"/> 28 <FrameLayout 29 android:id="@+id/for_secondfragment" 30 android:layout_width="wrap_content" 31 android:layout_height="wrap_content"></FrameLayout> 32 <fragment 33 android:id="@+id/first_fragment" 34 android:name="com.example.zhouy.androidexercise.MyFirstFragment" 35 android:layout_width="match_parent" 36 android:layout_height="match_parent" /> 37 </LinearLayout>
然后,在MyActivity中添加一个addFragment方法。具体代码如下
1 import android.app.Activity; 2 import android.app.Fragment; 3 import android.app.FragmentManager; 4 import android.app.FragmentTransaction; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.View; 8 import android.widget.Button; 9 import android.widget.FrameLayout; 10 11 public class MyActivity extends Activity implements View.OnClickListener { 12 13 private Button mAddSecondBtn = null; 14 15 private FrameLayout mFragment = null; 16 17 private FragmentManager mFragmentManager = null; 18 19 private FragmentTransaction mTransaction = null; 20 21 private Fragment mSecondFragment = null; 22 23 @Override 24 protected void onCreate(Bundle savedInstanceState) { 25 super.onCreate(savedInstanceState); 26 setContentView(R.layout.activity_my); 27 mAddSecondBtn = (Button)findViewById(R.id.add_by_framelayout); 28 mAddSecondBtn.setOnClickListener(this); 29 mFragment = (FrameLayout)findViewById(R.id.for_secondfragment); 30 //a.获取FragmentManager 31 mFragmentManager = getFragmentManager(); 32 33 } 34 35 private void addSecondFragment(){ 36 if(null == mSecondFragment){ 37 mSecondFragment = new MySecondFragment(); 38 } 39 if(null != mFragment){ 40 Log.v("Tag","开始添加fragment"); 41 //b.获取Transaction 42 mTransaction = mFragmentManager.beginTransaction(); 43 //c.添加Fragment 44 mTransaction.add(R.id.for_secondfragment,mSecondFragment); 45 //d.提交添加 46 mTransaction.commit(); 47 } 48 } 49 50 @Override 51 public void onClick(View view) { 52 switch (view.getId()){ 53 case R.id.add_by_framelayout: 54 addSecondFragment(); 55 break; 56 } 57 } 58 }
当然这部分代码存在一点儿问题,待会儿再说,我们先运行一下看看结果。点击添加按钮,结果如下
然而当我们再点击一下添加就会出现程序运行停止,看看LogCat日志出现了异常,说得很明白是已经添加了一个Fragment,这就是刚才所说的小问题。那么如何避免重复添加呢,我们稍微修改下addFragment方法就可以解决掉这个问题。修改后的方法如下。
1 private void addSecondFragment(){ 2 MySecondFragment fragment = (MySecondFragment) mFragmentManager. 3 findFragmentById(R.id.for_secondfragment); 4 if(null == mSecondFragment){ 5 mSecondFragment = new MySecondFragment(); 6 } 7 if(null == fragment ){ 8 Log.v("Tag","开始添加fragment"); 9 //b.获取Transaction 10 mTransaction = mFragmentManager.beginTransaction(); 11 //c.添加Fragment 12 mTransaction.add(R.id.for_secondfragment,mSecondFragment); 13 //d.提交添加 14 mTransaction.commit(); 15 } 16 }
剩下的删除和替换和添加Fragment步骤相似,就是remove和replace的区别。具体替换和删除方法代码如下
private void removeSecondFragment(){ MySecondFragment fragment = (MySecondFragment) mFragmentManager. findFragmentById(R.id.for_secondfragment); if(null != fragment ){ //b.获取Transaction mTransaction = mFragmentManager.beginTransaction(); //c.删除Fragment mTransaction.remove(fragment); //d.提交添加 mTransaction.commit(); } } private void replaceSecondFragment(){ Fragment fragment = (Fragment) mFragmentManager. findFragmentById(R.id.for_secondfragment); if(null != fragment ){ //b.获取Transaction mTransaction = mFragmentManager.beginTransaction(); //c.替换Fragment mTransaction.replace(R.id.for_secondfragment,new MyFirstFragment()); //d.提交添加 mTransaction.commit(); } }
Fragment的back栈
有时,用户在按back键时,需要回退到前一个布局,同样的也要回到之前已执行的Transaction。Android提供了addToBackStack来将Fragment添加到back栈中。调用addToBackStack需要在commit之前调用。
比如修改replaceFragment方法,在replace之后,commit之前添加addToBackStack,在按back键时,界面会回到替换之前的界面。代码如下。
private void replaceSecondFragment(){ Fragment fragment = (Fragment) mFragmentManager. findFragmentById(R.id.for_secondfragment); if(null != fragment ){ //b.获取Transaction mTransaction = mFragmentManager.beginTransaction(); //c.替换Fragment mTransaction.replace(R.id.for_secondfragment,new MyFirstFragment()); String tag = null; mTransaction.addToBackStack(null); //将Fragment添加到栈中 //d.提交添加 mTransaction.commit(); } }