第十三课:Fragment 详解

Fragment

Android是在Android 3.0 (API level 11)开始引入Fragment的。

可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的生命周期,单独处理自己的输入,在Activity运行的时候可以加载或者移除Fragment模块。

可以把Fragment设计成可以在多个Activity中复用的模块。

当开发的应用程序同时适用于平板电脑和手机时,可以利用Fragment实现灵活的布局,改善用户体验。

   如图:

Fragment的特征

1.Fragment 总是作为 Activity 界面的组成部分。Fragment 可调用 getActivity() 方法获取它所在的 Activity(),Activity 可调用 FragmentManager 的 findFragmentById() 或 findFragmentByTag() 方法来获取 Fragment。

2.在 Activity运行过程中,可调用 FragmentManager 的 add()、remove()、replace() 方法动态地添加、删除或替换 Fragment

3.一个 Activity 可以同时组合多个 Fragment;反过来,一个 Fragment 也可以被多个 Activity 复用

4.Fragment 可以响应自己的输入时间,并拥有自己的生命周期,但它们的生命周期直接被其所属的 Activity 的生命周期控制


Fragment 与 Activity 通信

为了在 Activity 中更现实 Fragment,还必须将 Fragment 添加到 Activity 中。将 Fragment 添加到 Activity 中有如下两种方式:

1.在布局文件中使用 <fragment.../> 元素添加 Fragment,<fragment.../> 元素的 android:name 属性指定 Fragment 的实现类。

2.在 Java 代码中通过 FragmentTransation 对象的 add() 方法来添加 Fragment。

注1Activity 的getFragmentManager() 方法可返回 FragmentManager,FragmentManager 对象的 beginTransaction() 方法可开启并返回 FragmentTransaction 对象

注2:如果 import android.support.v4.app.FragmentManager; 那么使用的是:FragmentManager fragmentManager =getSupportFragmentManager();


将 Fragment 添加到 Activity 之后,Fragment 必须与 Activity 交互信息,这就需要 Fragment 能获取它所在的 Activity,Activity 也能获取它所包含的任意的 Fragment。可按如下方法进行:

1. Fragment 获取它所在的 Activity:调用 Fragment 的getActivity() 方法即可返回它所在的 Activity。

2. Activity 获取它所包含的 Fragment:调用 Activity 关联的FragmentManagerfindFragmentById(int id)或  findFragmentByTag(String tag)方法即可获取指定的 Fragment。(需要在 <fragment.../> 中指定 android:id 或者 android:tag 属性)

除此之外,Fragment 和 Activity 可能还需要相互传递数据,可按如下方法进行:

1. Activity 向 Fragment 传递数据:在 Activity 中创建 Bundle 数据包,并调用 Fragment 的 setArguments(Bundle bundle) 方法即可将 Bundle 数据包传递给 Fragment

2. Fragment 向 Activity 传递数据或者 Activity 需要在 Fragment 运行中进行实时通信:在 Fragment 中定义一个内部回调接口,再让包含该 Fragment 的 Activity 实现该回调接口,这样 Fragment 即可调用该回调方法将数据传给 Activity


Fragment 管理与 Fragment 事务

Activity 管理 Fragment 主要依靠 FragmentManager。FragmentManager 可以完成如下几方面的功能:

1. 使用findFragmentById(int id) 或  findFragmentByTag(String tag) 方法来获取指定的 Fragment。

2. 调用 popBackStack() 方法将 Fragment 从后台栈中弹出(模拟用户按下 BACK 按键)。

3. 调用 addOnBackStackChangeListener() 注册一个监听器,用于监听后台栈的变化。


如果需要添加、删除、替换 Fragment,则需要借助于 FragmentTransaction 对象,FtagmentTransaction 代表 Activity 对 Fragment 执行的多个改变。


获取 FragmentTransaction 的方式如下所示:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransation = frangmentManager.beginTransaction();


每个 FragmentTransaction 可以包含多个对 Fragment 修改,比如包含调用了多个 add()、remove()、和 replace() 操作,最后还要调用 commit() 方法提交事务即可。

在调用 commit() 之前,开发者也可调用 addToBackStack() 将事务添加到 back 栈,该栈由 Activity 负责管理,这样允许用户按 Back 按键返回到前一个 Fragment 状态。

//创建一个新的 Fragment 并打开事务
Fragment newFragment = new ExampleFragment();
FragmentTransaction transation = getFragmentManager().beginTransaction();
//替换该界面中 fragment_container 容器内的 Fragment
transaction.replace(R.id.fragment_container, newFragment);
//将事务填加到 back 栈,允许用户按 BACK 按键返回到替换 Fragment 之前的状态
transaction.addToBackStack(null);
//提交事务
transaction.commit();


Fragment 的生命周期

因为Fragment必须嵌入在Acitivity中使用,所以Fragment的生命周期和它所在的Activity是密切相关的。

如果Activity是暂停状态,其中所有的Fragment都是暂停状态;如果Activity是stopped状态,这个Activity中所有的Fragment都不能被启动;如果Activity被销毁,那么它其中的所有Fragment都会被销毁。

但是,当Activity在活动状态,可以独立控制Fragment的状态,比如加上或者移除Fragment。

当这样进行fragment transaction(转换)的时候,可以把fragment放入Activity的back stack中,这样用户就可以进行返回操作。

 


1. 使用Support Library

  Support Library 是一个提供了 API 库函数的J AR 文件,这样就可以在旧版本的 Android 上使用一些新版本的 APIs。

  比如 android-support-v4.jar.它的完整路径是:

  <sdk>/extras/android/support/v4/android-support-v4.jar.

  它就提供了 Fragment 的 APIs,使得在 Android 1.6 (API level 4) 以上的系统都可以使用 Fragment。

  为了确定没有在旧版本系统上使用新版本的 APIs,需要如下导入语句:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;

  同时应该将上述的包拷入 libs 项目下的 libs 文件夹,然后在项目的 Properties 中添加:右键单击项目,选 Properties,左边选 Java Build Path,然后 Add External JARs…,添加 android-support-v4.jar.

 

当创建包含 Fragment 的 Activity 时,如果用的是 Support Library,那么继承的就应该是 FragmentActivity 而不是 Activity。

2. 必须实现的三个回调函数

  1. onCreate()

  系统在创建 Fragment 的时候调用这个方法,这里应该初始化相关的组件,一些即便是被暂停或者被停止时依然需要保留的东西。

  2. onCreateView()

  当第一次绘制 Fragment 的 UI 时系统调用这个方法,必须返回一个 View,如果 Fragment 不提供 UI 也可以返回 null。

  注意,如果继承自 ListFragment,onCreateView() 默认的实现会返回一个 ListView ,所以不用自己实现。

  3. onPause()

  当用户离开 Fragment 时第一个调用这个方法,需要提交一些变化,因为用户很可能不再返回来。

3. 实现 Fragment 的 UI

提供 Fragment 的 UI,必须实现 onCreateView() 方法。

假设 Fragment 的布局设置写在 example_fragment.xml 资源文件中,那么 onCreateView() 方法可以如下写:

public static class ExampleFragment extends Fragment
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
  Bundle savedInstanceState)
    {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.example_fragment, container, false);
    }
}

onCreateView() 中 container 参数代表该 Fragment 在 Activity 中的父控件;savedInstanceState 提供了上一个实例的数据。

inflate() 方法的三个参数:

第一个是resource ID,指明了当前的Fragment对应的资源文件;

   第二个参数是父容器控件;

   第三个布尔值参数表明是否连接该布局和其父容器控件,在这里的情况设置为false,因为系统已经插入了这个布局到父控件,设置为true将会产生多余的一个View Group。

 

例:

ExampleFragment.java

<span style="font-size:10px;">public class ExampleFragment extends Fragment
{

    //三个一般必须重载的方法
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        System.out.println("ExampleFragment--onCreate");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState)
    {
        System.out.println("ExampleFragment--onCreateView");
        return inflater.inflate(R.layout.example_fragment_layout, container, false);
        
    }

    @Override
    public void onPause()
    {
        // TODO Auto-generated method stub
        super.onPause();
        System.out.println("ExampleFragment--onPause");
    }

    

    @Override
    public void onResume()
    {
        // TODO Auto-generated method stub
        super.onResume();
        System.out.println("ExampleFragment--onResume");
    }

    @Override
    public void onStop()
    {
        // TODO Auto-generated method stub
        super.onStop();
        System.out.println("ExampleFragment--onStop");
    }
    
    

}</span>

example_fragment_layout.xml

<?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="vertical" >
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/num1"
           />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/num2"
        />  
    

</LinearLayout>


LearnFragment.java

public class LearnFragment extends FragmentActivity
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_learn_fragment);
        
        
        //在程序中加入Fragment
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        
        ExampleFragment fragment = new ExampleFragment();
        fragmentTransaction.add(R.id.linear, fragment);
        fragmentTransaction.commit();
    }

}


activity_learn_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <Button
        android:id="@+id/btn1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/btn1"      
        />

    <fragment 
        android:name="com.example.learningfragment.ExampleFragment"
        android:id="@+id/fragment1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        />
    <Button
        android:id="@+id/btn2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/btn2"      
        />

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/linear"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
     <Button
        android:id="@+id/btn3"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/btn3"      
        />
     </LinearLayout>

</LinearLayout>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值