Android里Fragment的相关知识(一)

定义

Android在3.0后引入了Fragment,我们唤它叫碎片或片段。当初主要是为了给大屏幕(如平板电脑)上更加动态和灵活的UI设计提供支持。例如,新闻应用可以使用一个Fragment在左侧显示文章列表,使用另一个Fragment在右侧显示文章,两个Fragment并排显示在一个Activity中,每个Fragment都具有自己的一套生命周期回调方法,并各自处理自己的用户输入事件。因此,用户不需要使用一个Activity来选择文章,然后使用另一个Activity来阅读文章,而是可以在同一个Activity内选择文章并进行阅读。后来随着应用功能越来越多,界面越来越复杂,Fragment被普通利用在对Activity界面进行UI模块化的使用。

一个Fragment是可以在多个Activity中复用的,所以在设计Fragment时,您应该尽量考虑把它设计为可重复使用的模块化 Activity 组件。也就是说,由于每个Fragment都会通过各自的生命周期回调来定义其自己的布局和行为,还要避免直接从某个Fragment直接操纵另一个Fragment。这特别重要,因为模块化片段让您可以通过更改Fragment的组合方式来适应不同的屏幕尺寸。在设计可同时支持平板电脑和手机的应用时,您可以在不同的布局配置中重复使用您的Fragment,以根据可用的屏幕空间优化用户体验。例如,在手机上,如果不能在同一 Activity 内储存多个Fragment,可能必须利用单独Fragment来实现单窗格 UI。

Fragment的生命周期

要想创建Fragment,您必须创建Fragment的子类。Fragment类的代码与Activity非常相似。它包含与 Activity 类似的回调生命周期方法,下图是官方文档中关于Fragment和Activity生命周期的对比:

可以看到Fragment比Activity多了几个额外的生命周期回调方法:

onAttach()                                    当Fragment与Activity建立关联时调用

onCreate()

onCreateView()                       用于创建Fragment的视图

onActivityCreated()            当Activity的onCreate()方法被返回时调用

当Fragment变得可见时,会经历以下状态:

 onStart()

onResume()

当Fragment进入后台模式时,会经历以下状态:

onPause()

onStop()

当Fragment被销毁(它当前所在的Activity被销毁)时,会经历以下状态:

onDestroyView()                   当Fragment的视图被移除时调用

onDestroy()

onDetach()                              当Fragment与Activity的关联被移除时调用

与Activity一样,可以使用Bundle对象在以下状态中还原Fragment的实例:

 onCreate()

onCreateView()

onActivityCreated()

与Activity生命周期回调方法的先后顺序

Fragment创建到激活过程与Activity相关的生命周期:

Activity

顺序

Fragment

onCreate

<-1

 

 

2->

onAttach

onAttachFragment

<-3

 

 

4->

onCreate

 

5->

onCreateView

 

6->

onActvitiyCreated

onStart

<-7

 

 

8->

onStart

onResume

<-9

 

 

10->

onResume

Fragment销毁过程与Activity相关的生命周期:

Activity

顺序

Fragment

 

1->

onPause

onPause 

<-2

 

 

3->

onSaveInstanceState

onSaveInstanceState

<-4

 

 

5->

onStop

onStop

<-6

 

 

7->

onDestroyView

 

8->

onDestroy

 

9->

onDetach

onDetach

<-10

 

Fragment的使用

静态的使用Fragment

静态的意思就是在布局XML中预先定义好要使用的Fragment,我们来看看一个上下结构的使用Fragment示例步骤。

新建fragment_title.xml,用于title的布局:

<?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="40dp"
   android:background="@color/title"
   android:orientation="horizontal">
 
   <TextView
       android:id="@+id/txt_title1"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:gravity="center"
       android:text="标题1"
       android:textSize="20sp"
       android:textColor="@color/title_text"
       android:layout_weight="1"/>
 
   <TextView
       android:id="@+id/txt_title2"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
        android:gravity="center"
       android:text="标题2"
       android:textSize="20sp"
       android:textColor="@color/title_text"
       android:layout_weight="1"/>
 
</LinearLayout>

新建TitleFragment,使其继承Fragment,并在onCreateView中关联fragment_title.xml:

public class TitleFragment extends Fragment implements View.OnClickListener {
 
    private TextView mTxtTitle1;
    private TextView mTxtTitle2;
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_title, container, false);
 
       mTxtTitle1 = (TextView) view.findViewById(R.id.txt_title1);
       mTxtTitle1.setOnClickListener(this);
       mTxtTitle2 = (TextView) view.findViewById(R.id.txt_title2);
       mTxtTitle2.setOnClickListener(this);
 
        return view;
    }
 
    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.txt_title1) {
           Toast.makeText(getActivity(), "点击了标题1",Toast.LENGTH_SHORT).show();
        } else if (v.getId() == R.id.txt_title2) {
           Toast.makeText(getActivity(), "点击了标题2",Toast.LENGTH_SHORT).show();
        }
    }
}

同理新建fragment_content.xml和ContentFragment:

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:background="@color/content">
 
    <Button
        android:id="@+id/btn_content"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:textSize="30dp"
       android:text="内容"/>
 
</RelativeLayout>
public class ContentFragment extends Fragment {
 
    private Button mBtnContent;
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_content, container, false);
 
       mBtnContent = (Button) view.findViewById(R.id.btn_content);
       mBtnContent.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Toast.makeText(getActivity(), "点击了内容", Toast.LENGTH_SHORT).show();
            }
        });
 
        return view;
    }
}

这样两个Fragment都定义好,接下来就开始在Acitity中使用它们,修改activity_main.xml:

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayout 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:background="@color/title">
 
   <fragment
       android:id="@+id/fragment_title"
       android:name="完整包名.TitleFragment"
       android:layout_width="match_parent"
       android:layout_height="40dp" />
 
   <fragment
       android:id="@+id/fragment_content"
       android:name="完整包名.ContentFragment"
       android:layout_below="@id/fragment_title"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />
 
</RelativeLayout>

MainActivity不用修改什么,默认就好:

public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
    }
}

就这样,运行APP可见下图,而且可以看到所有的控件事件处理代码都由各自所在的Fragment去处理,这种代码独立分离使整个工程的代码的可读性、复用性和维护性都大大提升。

动态的使用Fragment

动态使用,就是向Activity代码中动态添加Fragment,可使用FragmentManager类。还需要在Activity中使用FragmentTransaction类来执行Fragment操作(如添加、删除或替换)。扩展上示例,新添加一个ContentFragment2:

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:background="@color/content">
 
    <Button
       android:id="@+id/btn_content2"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:textSize="30dp"
       android:text="内容2"/>
 
</RelativeLayout>

 

public class ContentFragment2 extends Fragment {
    privateButton mBtnContent;
 
    @Override
    public ViewonCreateView(LayoutInflater inflater, ViewGroup container, BundlesavedInstanceState) {
        Viewview = inflater.inflate(R.layout.fragment_content2, container, false);
 
       mBtnContent = (Button) view.findViewById(R.id.btn_content2);
       mBtnContent.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Toast.makeText(getActivity(), "点击了内容2",Toast.LENGTH_SHORT).show();
            }
        });
 
        returnview;
    }
}

修改activity_main.xml,在内容的Fragment中用FrameLayout替换fragment:

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns: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:background="@color/title">
 
   <fragment
       android:id="@+id/fragment_title"
       android:name="完整包名.TitleFragment"
       android:layout_width="match_parent"
       android:layout_height="40dp" />
 
   <!--<fragment-->
       <!--android:id="@+id/fragment_content"-->
       <!--android:name="完整包名.ContentFragment"-->
       <!--android:layout_below="@id/fragment_title"-->
       <!--android:layout_width="match_parent"-->
       <!--android:layout_height="match_parent" />-->
 
   <FrameLayout
       android:id="@+id/fragment_content"
       android:layout_below="@id/fragment_title"
       android:layout_width="match_parent"
       android:layout_height="match_parent" />
 
</RelativeLayout>

修改MainActivity,使用FragmentManager 和 FragmentTransaction来执行Fragment操作:

public class MainActivity extends Activity implements View.OnClickListener {

    private TextView mTxtTitle1;
    private TextView mTxtTitle2;

    private ContentFragment mContentFragment;
    private ContentFragment2 mContentFragment2;

    private FragmentManager mFragmentManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTxtTitle1 = (TextView) findViewById(R.id.txt_title1);
        mTxtTitle1.setOnClickListener(this);
        mTxtTitle2 = (TextView) findViewById(R.id.txt_title2);
        mTxtTitle2.setOnClickListener(this);

        // 判断空为了防止屏幕翻转时重复添加Fragment
        if (savedInstanceState == null) {
            addContentFragment1();
        }
    }

    private void addContentFragment1() {
        if (mFragmentManager == null) {
            mFragmentManager = getFragmentManager();
        }
        if (mContentFragment == null) {
            mContentFragment = new ContentFragment();
        }
        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragment_content, mContentFragment);
        fragmentTransaction.commit();
    }

    private void addContentFragment2() {
        if (mFragmentManager == null) {
            mFragmentManager = getFragmentManager();
        }
        if (mContentFragment2 == null) {
            mContentFragment2 = new ContentFragment2();
        }
        FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragment_content, mContentFragment2);
        fragmentTransaction.commit();
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.txt_title1) {
            addContentFragment1();
        } else if (v.getId() == R.id.txt_title2) {
            addContentFragment2();
        }
    }
}

这样修改后,通过点击TitleFragment中的标题1和标题2就能分别切换到ContentFragment和ContentFragment2了

Fragment常用类简介

android.app.Fragment                        //用于定义Fragment

android.app.FragmentManager           // 用于在Activity中操作Fragment

android.app.FragmentTransaction       // 用于以事务方式执行Fragment的各种操作

如果在Android3.0或以下中使用时,应该使用兼容包:

importandroid.support.v4.app.Fragment;

importandroid.support.v4.app.FragmentManager;

importandroid.support.v4.app.FragmentTransaction;

Fragment常用方法简介

FragmentManagerfragmentManager = getFragmentManager();                                     //获取FragmentManage对象,如果在v4中,可以使用getSupportFragmentManager

FragmentTransactionfragmentTransaction =mFragmentManager.beginTransaction();      //表示开启Fragment事务

fragmentTransaction.commit();                                                                                         //表示提交Fragment事务 

fragmentTransaction.add()            //Activity中添加一个Fragment,可多次执行便是添加多个Fragment

fragmentTransaction.remove()     //Activity中移除一个Fragmen

fragmentTransaction.replace()       //本质上相当于调用了remove()方法,然后调用其add()方法

fragmentTransaction.hide()           //隐藏Fragment,注意是隐藏,并不是销毁

fragmentTransaction.show()          //显示隐藏的Fragment

fragmentTransaction.detach()       //UI中分离Fragment,remove()不同,此时Fragment的状态依然由FragmentManager维护。或者说,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构。场景上,如果当前Activity一直存在,但不希望保留用户操作时,可以优先使用detach

fragmentTransaction.attach()       //将分离的Fragment重新附加到UI上并显示

FragmentActivity

开头介绍时说到,Fragment是Android3.0后才引入的,所以在3.0之前是没有Fragment的,所以继承自Activity的FragmentActivity便是为解决3.0之前想使用Fragment而出现在android-support-v4.jar兼容包里的一个类。它的用法基本跟Fragment一样,目前已知不同的是在获取FragmentManage对象使用getSupportFragmentManager()方法,而不是getFragmentManager() 。 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值