Android Fragment使用详解

Fragment介绍

Android在3.0中引入了Fragments的概念,主要目的是用在大屏幕设备上(如平板电脑上)支持更加动态和灵活的UI设计。平板电脑的屏幕要比手机大,有更多的空间来放更多的UI组件,并且这些组件之间会产生更多的交互,Fragment在应用中应该是一个模块化和可重用的组件,因为Fragment定义了它自己的布局,已经通过使用它自己的生命周期回调方法定义了他自己的行为,也可以将Fragment包含到多个Activity中。更多详细介绍可查看官方文档

Fragment知识概要

1、Fragment可以作为Activity界面的一部分组成出现。
2、可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity 中使用。
3、在Activity运行过程中,可以添加,移除和替换Fragment。
4、Fragment可以响应自己的输入事件,并且有自己的生命周期,他们的生命周期受宿主Activity生命周期的影响和限制。

创建一个Fragment

创建一个Fragment,必须创建一个Fragment子类或继承已存在的子类,创建好子类后可在onCreateView()方法中加载Fragment中的布局文件,Fragment第一次绘制它的用户界面的时候,系统会调用此方法,为了绘制Fragment的UI,此方法必须返回一个View,如果不显示UI,返回null即可。

public class MyFragment extends Fragment{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        //在这里加载Fragment的布局文件,将其转换成View对象最后返回,(下面有详细的案例)...

        return super.onCreateView(inflater, container, savedInstanceState);
    }
}

Activity加载Fragment两种的方式(静态加载、动态加载)

静态加载:

在Activity的layout文件中声明Fragment,需要特别注意的是在标签中的需要包含一个android:name属性来指定这个layout中实例化的Fragment类(把Fragment的全类名写在这个属性里面),同时也要给这个Fragment一个唯一的标识。

标识一个Fragment的方法(两种):

  • android:id属性提供一个唯一ID
  • android:tag属性提供一个唯一字符串

1、在Activity的layout文件中声明Fragment

<?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" >

    <fragment
        android:id="@+id/fragment"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:name="com.example.android_fragment.MyFragment"/>

</LinearLayout>

2、创建Fragment标签中name属性指定的Fragment类

public class MyFragment extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        //加载Fragment自己的布局文件并转换成View对象
        View view = inflater.inflate(R.layout.myfragment, container, false);

        //注意findViewById前的view
        TextView text=(TextView) view.findViewById(R.id.text);
        Button button=(Button) view.findViewById(R.id.button);

        //.........

        return view;
    }
}

Fragment的布局文件

<?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" >

    <!-- MyFragment对应的布局文件 -->

    <TextView 
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button 
        android:text="改变"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button" />

</LinearLayout>

以上就是在Activity中加载布局文件是会静态加载Fragment,注:在Activity中也可以通过findViewById查找Fragment中的布局控件。

动态加载

动态加载需要撰写代码将Fragment添加到一个Activity layout中,add()添加一个Fragment(指定要添加的fargment和插入的View),与此类似的还有remove(),replace()。

要完成动态Fragment加载还需要处理Fragment事务,根据用户的交互情况,对Fragmeeng进行添加,移除,替换以及执行其他动作,提交给Activity的每一套变化被称作一个事务。获取Fragment事务代码如下:

FragmentManager  fragmentManager = getFragmentManager();
FragmentTransaction  beginTransaction = fragmentManager.beginTransaction();

每一个事物都是同时执一套变化,可以在一个事物中设置你所有想执行的变化,包括add(),remove(),replace(),然后提交给Activity,必须调用commit()方法(和数据库事务提交类似)

如果允许用户通过按下BACK按键返回到前一个Fragment状态,调用commit()之前可以加入addToBackStack()方法。

1、创建一个Fragment

public class MyFragment2 extends Fragment{

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        //加载Fragment自己的布局文件并转换成View对象
        View view = inflater.inflate(R.layout.myfragment, container, false);
        TextView text=(TextView) view.findViewById(R.id.text);
        text.setText("动态加载Fragment");
        //................
        return view;
    }
}

这时就不需要在Activity的布局文件中声明Fragment标签,而是Activity中使用代码将他添加到布局文件中来

MyFragment2 fragment2=new MyFragment2();
FragmentManager fragmentManager = getFragmentManager();//获得fragment管理者
FragmentTransaction beginTransaction = fragmentManager.beginTransaction();//开启事务
beginTransaction.add(R.id.frame, fragment2);//第一个参数为要把fragment加载到那个布局中
beginTransaction.addToBackStack(null);//按back键可回退上一个fragment状态
beginTransaction.commit();//提交事务    

Fragment生命周期

在学习Fragment声明周期前我们应该要了解Activity的生命周期,Fragment作为Activity的一部分所以他的生命周期一定会受到宿主Activity生命周期的影响。

Fragment声明周期图
这里写图片描述

Fragment与Activity生命周期对比图
这里写图片描述

通过上面的Fragment与Activity生命周期对比图可以看出每个Activity生命周期所对应的状态下都会至少对应一个Fragment生命周期的回调方法。接下来就对Fragment的所有生命周期方法进行了解。(直接在代码中解释)

public class MyFragment3 extends Fragment {

    private TextView tv;

    // 启动Fragment——>屏幕锁屏——>屏幕解锁——>
    // 切换到其他的Fragment——>回到桌面——>回到应用——>退出Fragment
    /**
     * 每次创建都会绘制Fragment的View组件时回调该方法(在onCreate和onActivityCreated之间调用)
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        View view = inflater.inflate(R.layout.fragment2, container, false);
        TextView tv = (TextView) view.findViewById(R.id.text);
        tv.setText("第一个Fragment");
        Log.i("Main", "Fragment1---onCreateView()");
        return view;
    }

    /**
     * 当Fragment被添加到Activity时候会回调这个方法,并且只调用一次
     */
    @Override
    public void onAttach(Activity activity) {
        // TODO Auto-generated method stub
        super.onAttach(activity);
        Log.i("Main", "Fragment1---onAttach()");

    }

    /**
     * 创建Fragment时会回调,只会调用一次
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("Main", "Fragment1---onCreate()");

    }

    /**
     * 当Fragment所在的Activty启动完成后调用
     */
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.i("Main", "Fragment1---onActivityCreated()");

    }

    /**
     * 启动Fragment
     * 
     */
    @Override
    public void onStart() {
        super.onStart();
        Log.i("Main", "Fragment1---onStart()");

    }

    /**
     * 恢复Fragment时会被回调,调用onStart()方法后面一定会调用onResume()方法
     */
    @Override
    public void onResume() {
        super.onResume();
        Log.i("Main", "Fragment1---onResume()");

    }

    /**
     * 暂停Fragment
     */
    @Override
    public void onPause() {
        super.onPause();
        Log.i("Main", "Fragment1---onPause()");

    }

    /**
     * 停止Fragment
     */
    @Override
    public void onStop() {
        super.onStop();
        Log.i("Main", "Fragment1---onStop()");

    }

    /**
     * 销毁Fragment所包含的View组件时,和onCreateView所创建的View组件对应
     */
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.i("Main", "Fragment1---onDestroyView()");

    }

    /**
     * 销毁Fragment时会被回调
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("Main", "Fragment1---onDestroy()");

    }

    /**
     * Fragment从Activity中删除时会回调该方法,并且这个方法只会调用一次
     */
    @Override
    public void onDetach() {
        super.onDetach();
        Log.i("Main", "Fragment1---onDetach()");
    }
}

上面对Fragment的生命周期已经做了详细的介绍,下面可以通过一个案例来演示来详细了解以下操作对Fragment的生命周期的影响。(直接贴测试结果)

启动fragment

onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()

屏幕锁屏或按HOME键回到手机主界面

onPause()->onStop()

屏幕解锁或长按HOME重新回到应用(Fragment)

onStart()->onResume()

退出Fragment

onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()

第一个Fragment切换到第二个Fragment (相对于第一个Fragment替换第二个Fragment)

第一个fragment调用的方法:

onPause()->onStop()->onDestoryView()->onDestory()->onDetach();

第二个fragment调用的方法:

onAttach()->onCreate()->onCreateView()->onActivityCreated()->onStart()->onResume()

Fragment的生命周期方法

1、onAttach(); // 当fragment被添加到activity中时会回调这个方法;只会调用一次
2、onCreate(); // 在fragment创建的时候回调这个方法;只会调用一次;
3、onCreateView(): // 每次创建都会绘制Fragment的View组件时调用该方法,相当于fragment绑定一个布局,布局文件转换成view返回回来;
4、onActivityCreated(); // fragment所在的activity启动完成后调用;
5、onStart(): // 启动Fragment时会被回调,
6、onResume(); // 调用onStart()方法后面一定会调用这个方法,恢复fragment时回调
7、onPause(): // 暂停Fragment
8、onStop(); // 停止Fragment
9、onDestroyView(): // 销毁Fragment所包含的View组件,与onCreateView相对应
11、onDetach(): // Fragment从Activity中删除时回调这个方法,并且只调用一次
10、onDestroy(): // 销毁Fragment时会被回调

Fragment与Activity通信

知识点:

如果想在彼此之间建立通信,首先就要咋彼此的地盘中找到对方

1、在fragment可调用getActivity()方法获取他所在的宿主Activity
2、Acitvity可调用FragmentManager的findFragmentById()或findFragmentByTag()方法获取Fragment

在Fragment与Activity通信都会传递一些数据

1、Activity传递数据到Fragment:在Activity中创建Bundle数据包,并调用Fragment的setArguments(Bundle bundle)方法,然后在Fragment类里面通过getArguments方法获取Bundle数据包。

2、Fragment传递数据到Activity:需要在Fragment中定义一个内部回调接口,再让包含该Fragment的Activity实现该回调接口。这样Fragment可调用该回调方法将数据传递给Activity。

示例代码:

Activity向动态加载的Fragment传值(而且是在Fragment添加到Layout布局之前发送数据):

MyFragment5 fragment5 = new MyFragment5();
Bundle bundle = new Bundle();
bundle.putString("name", text);
fragment5.setArguments(bundle);

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction beginTransaction = fragmentManager.beginTransaction();
beginTransaction.add(R.id.layout, fragment5, "fragment5");//在动态加载时设置FragmentTag(fragment5)
beginTransaction.commit();

动态加载的Fragment取值:

String text=getArguments().get("name")+""   ;
//向静态加载fragment传值
FragmentManager fragmentManager = getFragmentManager();
Fragment findFragmentById = fragmentManager.findFragmentById(R.id.frag);//查找已加载进来的fragment
MyFragment frag=(MyFragment) findFragmentById;//类型转换     
frag.setAaa("fragment静态传值");//调用MyFragment中接收数据变量的set方法将数据进去,在Fragment中直接调用get方法获取数据

静态加载的Fragment取值:

public class MyFragment extends Fragment{

    private String aaa;

    public String getAaa() {
        return aaa;
    }

    public void setAaa(String aaa) {
        this.aaa = aaa;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.myfragment, container, false);

        String value = getAaa();//获取传递过来的值

        return view;
    }
}

Fragment向Activity传递数据

public class MyFragment5 extends Fragment{

    private String code="Thank you,Activity!";

    public MyListener listener;//3.为接口声明一个对象

    //1.内部回调接口(为了向Activity传递数据),让Activity实现该接口极其方法
    public interface MyListener
    {
        public void thank(String code);
    }

    /**
     * 2.实现Fragment生命周期的onAttach方法
     * 当Fragment被添加到Activity时候会回调这个方法,并且只调用一次
     */
    @Override
    public void onAttach(Activity activity) {
        listener=(MyListener) activity;//引用宿主Activity对象
        super.onAttach(activity);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment2, container, false);

       //直接通过listener(Activity)对象的的thank方法向Activity传值
        listener.thank(code);

        return view;
    }
}

Activity接收数据

public class MainActivity extends Activity implements MyListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

    }

    @Override
    public void thank(String code) {
        // 在接口实现的方法中得到Fragment中传过来的数据
        Toast.makeText(MainActivity.this,  code,Toast.LENGTH_SHORT).show();
    }
}

上述已经介绍完成了Fragment常用的一些方法,相信看完,大家一定清楚了Fragment的产生理由,以及如何使用Fragment,最后需要说一下Fragment的例子,Android官方已经提供了Fragment的各种使用的Demo例子,在我们SDK下面的API Demo里面就包含了Fragment的各种使用例子,需要看Demo的朋友,直接看API Demo那个程序就可以了,不用到处去找。里面分开不同功能,实现了不同的类。可以根据需要查看具体代码。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值