✏️
Android应用开发
  • 简介
  • 目录
  • 第一章 熟悉Android Studio开发环境
    • 第一个项目——Hello World!
    • 第二个项目——计数器
    • 第三个项目——新闻阅读器
  • 第二章 活动、组件及布局
    • 第四个项目——消息发送
    • 第五个项目——计数器2
    • 第六个项目——登陆界面
    • 第七个项目——新闻列表
  • 第三章 数据持久化
    • 第八个项目——登陆界面2
    • 第九个项目——新闻列表2
  • 第四章 内容提供器与数据共享
    • 第十个项目——音乐播放器1
  • 第五章 多媒体与服务
    • 第十一个项目——音乐播放器2
    • 第十二个项目——音乐播放器3
  • 第六章 绑定服务与自定义广播
    • 第十三个项目——音乐播放器4
  • 第七章 网络与多线程
    • 第十四个项目——新闻列表3
  • 附录 扩展项目
    • 第十五个项目——使用ViewHolder提升ListView显示性能
    • 第十六个项目——使用SwipeRefreshLayout实现下拉刷新
    • 第十七个项目——使用接口回调实现删除ListView列表中的Item数据
    • 第十八个项目——使用RecyclerView显示列表数据
    • 第十九个项目——使用Fragment组织UI页面
    • 第二十个项目——使用CursorAdapter进行数据绑定及渲染
    • 第二十一个项目——使用Loader实现异步数据加载操作
    • 第二十二个项目——使用TimerTask及Handler实现秒表计时器
    • 第二十三个项目——使用AsyncTask进行网络异步请求
Powered by GitBook
On this page
  • 实验目的
  • 实验要求
  • 实验内容
  • 步骤一,打开第七个项目
  • 步骤二,新建NewsListFragment类
  • 步骤三,更改fragment_news_list.xml布局文件
  • 步骤四,修改NewsListFragment类定义
  • 步骤五,加载Fragment
  • 步骤六,编译并运行项目
  • 附:Fragment动态加载
  • 实验小结

Was this helpful?

  1. 附录 扩展项目

第十九个项目——使用Fragment组织UI页面

Previous第十八个项目——使用RecyclerView显示列表数据Next第二十个项目——使用CursorAdapter进行数据绑定及渲染

Last updated 4 years ago

Was this helpful?

实验目的

  • 掌握Fragment组件的使用方法;

  • 掌握Fragment与Activity组件的交互方式;

实验要求

  • 使用Fragment实现新闻列表加载

实验内容

Fragment中文名为片段或碎片,它可视为Activity UI页面中的部分或轻量级的Activity,其具备与Activity相似的生命周期。通过Fragment可将原有的Activity的UI页面进行划分,提升UI页面的可重用性以及适配性。本实验通过Fragment对中新闻列表页面进行重构,介绍Fragment的基本使用方法。

使用Fragment时,需要从自定义Fragment子类,并至少需要重写下列三个方法:

  • onCreate(),与Activity中的onCreate()方法相似,该方法在创建Fragment实例时被回调,

    通常进行Fragment中组件的初始化;

  • onCreateView(),该方法在当需要Fragment绘制UI时被调用,方法需要返回Fragment的UI布局根视图;

  • onPause(),该方法在用户离开FragmentUI页面时被调用,通常进行数据持久化或组件销毁;

除了上述三个方法必须进行重写外,Fragment还包含了与生命周期相关的其他几个回调函数,详见官方开发文档。

步骤一,打开第七个项目

步骤二,新建NewsListFragment类

完成新建操作后,在项目中将生成NewsListFragment.java以及fragment_news_list.xml两个文件,分别对应 Fragment的源文件以及布局文件。

/**
 * A simple {@link Fragment} subclass.
 */
public class NewsListFragment extends Fragment {

    public NewsListFragment() {
            // Required empty public constructor
    }

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

步骤三,更改fragment_news_list.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/lv_news_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:scrollbars="none"
        android:layout_margin="8dp"
        android:divider="@android:color/transparent"
        android:dividerHeight="8dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />
</android.support.constraint.ConstraintLayout>

步骤四,修改NewsListFragment类定义

在NewsListFragment中实现新闻列表加载功能,主要思路是将原MainActivity中的业务代码逐一剪切复制到NewsListFragment当中。

1. 将titles、newsAdapter等对象声明复制到NewsListFragment中

将titles、newsList、newsAdapter等对象申明从MainActivity剪切复制到NewsListFragment中。

2. 将initData()方法复制到NewsListFragment中

将initData()方法定义从MainActivity剪切复制到NewsListFragment中。

3. 重写NewsListFragment的onCreate()方法

在NewsListFragment类中重写onCreate()方法,在其中调用initData()方法进行新闻列表数据初始化。

4. 重写NewsListFragment的onCreateView()方法

onCreateView()方法在Fragment绘制UI时被回调,该方法返回值为完成布局渲染的根视图元素。 为方便加载布局,该方法包含了三个参数:

  • LayoutInflater inflater,用于加载布局的LayoutInflater对象;

  • ViewGroup container,Fragment加载的布局应嵌入进的ViewGroup对象;

  • Bundle savedInstanceState,初始化所需的Bundle对象;

在NewsListFragment的onCreateView()方法中,首先,通过getActivity()获取到与绑定当前Fragment 的Activity对象,并将其作为Context上下文对象进行保存,便于后续使用;其次,通过LayoutInflater对象加载了fragment_news_list布局;最后,通过加载好的布局绑定ListView控件对象,并设置该对象所需的NewsAdapter适配器。

public class NewsListFragment extends Fragment {

    private Context context = null;

    private String[] titles = null;
    private String[] authors = null;
    private String[] contents = null;
    private TypedArray images;

    private List<News> newsList = new ArrayList<>();

    private NewsAdapter newsAdapter = null;
    private ListView lvNewsList;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        initData();
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
                    ViewGroup container,
                    Bundle savedInstanceState) {
        context = getActivity();
        View rootView = inflater.inflate(R.layout.fragment_news_list,
                                 container, false);    

        lvNewsList = rootView.findViewById(R.id.lv_news_list);
        newsAdapter = new NewsAdapter(context,
                                R.layout.list_item,
                                newsList);
        lvNewsList.setAdapter(newsAdapter);

        return rootView;
    }

    private void initData() {
        int length;

        titles = getResources().getStringArray(R.array.titles);
        authors = getResources().getStringArray(R.array.authors);
        images = getResources().obtainTypedArray(R.array.images);

        if (titles.length > authors.length) {
            length = authors.length;
        } else {
            length = titles.length;
        }

        for (int i = 0; i < length; i++) {
            News news = new News();
            news.setTitle(titles[i]);
            news.setAuthor(authors[i]);
            news.setImageId(images.getResourceId(i, 0));

            newsList.add(news);
        }
    }
}

完成将MainActivity的代码复制到NewsListFragment后,MainActivity类定义代码如下所示。

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

步骤五,加载Fragment

在Activity中加载Fragment有2种方式:

  • 静态加载,在Activity对应的布局中使用标签进行静态加载;

  • 动态加载,在Activity中使用FragmentManager、FragmentTransaction动态对Fragment进行数据加载及绑定;

本实验中使用静态加载的方式加载Fragment,打开activity_main.xml布局文件,由于在步骤三 中已经将原ListView标签从activity_main.xml中剪切复制到fragment_news_list.xml中,因此直接在 activity_main.xml根视图元素中加入标签,并通过android:name属性指定 所需加载的Fragment类名(包含包名),最终的布局文件代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:name="com.glriverside.xgqin.listviewdemo.NewsListFragment"
        android:id="@+id/news_list"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        />
</android.support.constraint.ConstraintLayout>

步骤六,编译并运行项目

附:Fragment动态加载

动态加载Fragment需要使用FragmentManager、FragmentTransaction两个组件。动态加载Fragment需要指定对应的ViewGroup视图容器,并通过FragmentTransaction完成事务操作。

1. 首先调整activity_main.xml布局文件

在activity_main.xml布局文件中,需要定义ViewGroup视图容器作为动态加载Fragment的根视图容器, 在本实验中,使用ConstraintLayout作为根视图容器,并指定其id属性为fragment_container, 具体代码如下所示。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.constraint.ConstraintLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fragment_container"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        >
    </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

2. 修改MainActivity的onCreate()方法

在Fragment 静态加载方式中,通过在布局文件中指定,当Activity被实例化时, 指定的Fragment将被实例化,且该Fragment对象对应的onCreate()、onCreateView()方法会被回调执行。

动态加载Fragment则需要通过FragmentTransaction碎片事务组件完成。 首先,需要获取FragmentManager对象; 其次,调用FragmentManager对象的beginTransaction()方法获得FragmentTransaction对象;在此基础上 调用FragmentTransaction对象的相应方法添加、替换Fragment至指定的ViewGroup视图容器;最后, 调用FragmentTransaction对象的commit()方法提交碎片事务,执行Fragment加载操作。

在该过程中,以下几个方法尤为重要:

  • getSupportFragmentManager(),获取FragmentManager对象;

  • FragmentManager.beginTransaction(),开始碎片事务,获得FragmentTransaction对象;

  • FragmentTransaction.add()或FragmentTransaction.replace(),

    添加或替换Fragment至指定ViewGroup视图容器;

  • FragmentTransaction.addToBackStack(),添加Fragment至返回栈;

  • FragmentTransaction.commit(),提交碎片事务;

如下代码所示,首先获取了FragmentManager对象,并开始FragmentTransaction碎片事务,再将实例化的NewsListFragment对象通过FragmentTransaction.add()方法添加到R.id.fragment_container视图容器中,最后通过FragmentTransaction.commit()提交碎片事务,完成Fragment动态加载操作。

public class MainActivity extends AppCompatActivity {
    FragmentManager fragmentManager;

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

        fragmentManager = getSupportFragmentManager();
        FragmentTransaction ft = fragmentManager.beginTransaction();

        NewsListFragment newsListFragment = new NewsListFragment();

        ft.add(R.id.fragment_container, newsListFragment);
        ft.commit();
    }    
}

实验小结

通过本次实验,你应该掌握了如下知识内容:

  • 使用Fragment组织UI界面及逻辑;

  • 使用FragmentManager、FragmentTransaction进行Fragment动态加载;

打开,在该项目的基础上完成本次实验。

在Project窗口中选择app/java文件夹,右击选择【New】->【Fragment】->【Fragment(Blank)】,在弹出的 New Android Component对话框中Fragment Name文本框中输入NewsListFragment, 勾选Create layout XML?、取消勾选Include fragment factory methods?及 Include interface callbacks复选框,点击【Finish】完成新建Fragment的创建, 具体如所示。

图1. 新建NewsListFragment

使用Fragment重构,主要是将原在MainActivity中各回调函数的业务代码相应的迁移到NewsListFragment相应的回调函数中,而原有activity_main.xml布局元素(除根视图元素外)也可一并迁移至fragment_news_list.xml文件中。

将中activity_main.xml布局文件中的ListView标签剪切并复制到fragment_news_list.xml文件中,具体代码如下所示。

编译并运行项目,其执行效果与相同。

第七个项目
第七个项目
第七个项目
第七个项目
第七个项目
图1. 新建NewsListFragment