Fragment的介绍和使用(一)

本文详细介绍了Fragment的概念、用途、生命周期及其在Android应用开发中的静态使用方法。阐述了Fragment如何帮助开发者处理不同屏幕尺寸下的界面布局问题,以及如何通过Fragment实现界面模块化。同时,文中通过实例展示了如何在不同屏幕大小下动态加载不同的布局,以充分利用屏幕空间。此外,还介绍了Fragment的生命周期回调方法及其实现过程,以及如何通过Fragment管理视图和不可视任务。最后,通过示例代码演示了如何在Activity中动态添加和移除Fragment,以提高界面的灵活性和复用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是Fragment

Fragment意为碎片,片段。在Google的官方文档介绍,Fragment是一个应用程序的用户界面的一部分或者用来执行某些行为。我们都知道,如果需要跟用户交互,都需要用到Activity,所以,Fragment必须是嵌入到Activity中。

我们可以把多个Fragment放到一个Activity里,也可以把一个Fragment在多个Activity里复用。我们可以理解FragmentActivity的一个模块。它包含自己的生命周期,可以响应它自己的交互事件。我们可以随意的在运行中的Activity中把加入或者移除Fragment。就像我们可以复用多个Activity一样。

为什么会有 Fragment

Fragment 是在 Android 3.0时加入的。Fragment 的出现一方面是为了缓解 Activity任务太重的问题;另一方面是为了处理在不同屏幕上UI组件的布局问题,尤其是大屏幕;而且它还提供了一些Activity不具有的新特性来处理一些在 开发中比较难解决的问题。

在开发中大型的应用时,如果遇到特别复杂的界面,Activity就会显得特别复杂,就会变得臃肿。如果使用FragmentActivity分割,就会很好的缓解这种情况。实际上Fragment不仅仅是界面,不仅仅是View;它实际上干的就是Activity的事情;它负责的是控制View和他们之间的逻辑。

Activity分割成多个Fragment后,Activity就可以脱出身来,不再去处理大量的View了,它只需要管理Fragment或者少量的View

Fragment 不仅仅可以管理View,也可以管理一些不可视的任务。比如在Activity因切换横竖屏而销毁重建时,它仍然可以保留实例。当然它的前提是必须要设置retainInstance属性。

虽然它是在Android 3.0时加入的,Google也提供了support包来支持之前的版本。这说明Google对Fragment的重视,并且提倡使用Fragment

初探 Fragment

上面提到Fragment一方面是为了处理在不同屏幕上UI组件的布局问题,尤其是大屏幕;如下图,是一个新闻app的界面示意图,为了更好的利用屏幕的空间,它要求在比较大的平板上,呈左面的显示方式,左面是一个新闻列表,点击某个新闻标题,在右面显示具体的新闻内容。如果在较小的手机上,就要呈右边的形式,首先显示的一个新闻列表,如果点击某个新闻标题,就在另一屏显示具体的新闻内容。
fragments

如果只用Activity实现,十分的麻烦,但是如果使用Fragment,就显得很简单了。我们可以先创建两个Fragment,一个NewsListFragment用来显示新闻列表,一个NewsDetailFragment用来显示新闻内容。它们的布局分别为
fragment_news_listfragment_news_detail;我们设置在Activity的布局时,可以根据屏幕的大小来编写两个布局,一个包含是右边的样式,一个是左面的样式。然后根据屏幕的大小设置最小宽度限定符,比如large/sw600dp,在程序加载的时候,会根据屏幕大小动态去选择需要的布局。具体的步骤我们会后面介绍。

###Fragment的生命周期
因为Fragment是依附于Activity的,那么它必然会受到Activity生命周期的影响。Google在官网给出了一张图来说明它们两者间生命周期的的关系。
fragment 生命周期

根据上图我们可以看出,FragmentActivity 多出几个额外的回调方法:

onAttach(Context):

Fragment第一次关联在Context上时调用。这里Context就是指的Activity

onCreateView(LayoutInflater, ViewGroup, Bundle):

看字面意思就可以知道,该方法是创建Fragment自己的视图。如果没有图像界面就可以返回null。该方法跟下面的 onDestroyView()相对应。

onActivityCreated(Bundle):

Fragment所附着的Activity创建完毕之后调用;并且这个Fragment的视图也会被实例化。这个方法可以用来做初始化或者用来恢复界面或者状态。

onDestroyView():

跟上面的 onCreateView()相对应。当Fragment的视图移除时调用。下一次要展示Fragment时,视图会重新创建。

onDetach():

跟上面的onAttach()相对应,当FragmentActivity关联被取消时调用

其它的几个跟Activity回调相同的,意思也跟Activity的回调的用法一样,这里就不一一解释了。

Fragment 的用法

Fragment静态用法:

在初探Fragment中提到的就是Fragment的静态使用方法。下面我们具体实现一下。

所谓静态就是在布局里面写死,不能在程序运行中,动态添加/移除Fragment
在初探Fragment时我们需要在不同屏幕大小实现显示不同的布局。

根据需求,我们首先实现一个实现最简单的只有一个新闻列表的布局,当然我们还是使用Fragment实现了。

以下的实现都是使用的 Android 3.0之后提供的Fragment,如果要支持以前的版本请将Activity替换成Support包中的FragmentActivity,导包的时候,要导入import android.support.v4.app.Fragment;

首先我们先创建一个Activity,叫做NewsActivity,继承自Activity,用于显示的布局叫做activity_news:

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

然后创建一个类去继承Fragment,我们暂且叫它NewsTitleListFragment。就像这样:

public class NewsTitleListFragment extends Fragment{
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }
}

这个Fragment是用来显示新闻标题列表的。我们还需要创建一个显示新闻列表的布局,我们使用ListView来展示列表。我们给它加个背景便于区别。具体如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
			  android:background="#ff11ffff"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <ListView
        android:id="@+id/lv_news_title_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

然后我们回到NewsTitleListFragment,在onCreateView()中我们来返回我们的布局视图。

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

我们通过LayoutInflater将布局转换为View,作为Fragment的视图。

下面我们准备一些数据,用来填充这个 ListView:

private String[] mTitles;

void initTitles() {
    mTitles = new String[10];
    for (int i = 0; i < 10; i++) {
        mTitles[i] = "Title = " + i;
    }
}

然后在onCreateView()绑定ListView :

mTitleList = (ListView) view.findViewById(R.id.lv_news_title_list);

并且设置适配器和行点击事件。在Fragment获取Activity可以使用getActivity:

ArrayAdapter adapter = new ArrayAdapter(getActivity(),android.R.layout.simple_list_item_1,mTitles);
mTitleList.setAdapter(adapter);
 mTitleList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            startActivity(getActivity(),NewsDetailActivity.class);
        }
    });

这里的NewsDetailActivity,只是一个展示界面就不在具体说了。很简单。

然后将NewsTitleListFragment使用fragment标签设置到NewsActivity的布局里:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <fragment
        android:id="@+id/fragment_news_list"
        android:name="com.liteng.app.fragments.lifecycle.NewsTitleListFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

</LinearLayout>

这里使用 android:name指向新建的NewsTitleListFragment

运行后是这样的:
TitleListFragment

但是我们要支持在大屏情况下显示的是两个部分:左边是列表,右边是内容。这就需要使用在我们适配时用到的large限定符。我们在res目录下,新建一个文件夹layout-large,然后在里面新建一个同样的布局activity_news,这样程序运行到大屏幕的设备上时就会自动去加载这个布局。

这样我就需要两个Fragment,我们类似的新建一个NewsDetailFragment,其界面布局为fragment_news_detail。这里我只是模拟一下新闻内容,不再具体做实现。

public class NewsDetailFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_news_detail, container, false);
        return view;
    }
} 

下面是布局内容:

<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"
              tools:context=".fragments.lifecycle.NewsListFragment">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="20dp"
        android:gravity="center"
        android:text="News Title"
        android:textSize="20sp"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="The Czech Republic sent two fighter jets to escort Xi's plane when it entered the country's airspace. Xi was received by Czech Foreign Minister Lubomir Zaoralek and other senior officials at the airport.Hailing the long-held friendship between the two countries, Xi, in his written remarks upon arrival, extended sincere greetings and best wishes to the Czech people."
        android:textSize="16sp"/>
</LinearLayout>

重点是Activity显示布局activity_news,我们在这里面放两个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="horizontal">

    <fragment
        android:id="@+id/fragment_news_list"
        android:name="com.liteng.app.fragments.lifecycle.NewsTitleListFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

    <fragment
        android:id="@+id/fragment_news_detail"
        android:name="com.liteng.app.fragments.lifecycle.NewsDetailFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>
</LinearLayout>

但是还有一个问题,我们如果在Activity里区分是大屏还是小屏,我们可以去判断有没有加载具体内容的NewsDetailFragment,来做区分,然后再去做具体操作;我们在NewsActivity里通过Fragment的id,来判断是否存在这个Fragment:

 Fragment fragmentNewsDetail = getFragmentManager().findFragmentById(R.id.fragment_news_detail);
    if (fragmentNewsDetail != null) {
        Log.e(TAG,"大屏");
    }else{
        Log.e(TAG,"小屏");
    }

如果大家对这里的 getFragmentManager().findFragmentById(R.id.fragment_news_detail),有疑惑,我们会在下一节具体介绍。

下面附上一张Activity和Fragment的完整生命周期图,如果有兴趣的话,可以看看。这张图是在网上找的,如果涉及到版权,我会及时删除。

Activity和Fragment的完整生命周期图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值