Andorid fragment 基本使用

132 阅读3分钟

原理

在其布局中为fragment的视图安排位置。
管理fragment实例的生命周期。

fragmnet生命周期

fragment的生命周期方法由托管activity而不是操作系统调用,fragment的使用是activity内部的事情。

image.png

activity托管UI fragment的方式

1. 在activity布局中添加fragment

  • 特点:使用布局fragment在activity布局中添加fragment
  • 缺点:将fragment及其视图与activity的视图绑定在一起,activity周期内无法替换fragment视图

2. 在activity代码中添加fragment(推荐)

  • 特点:可以动态控制fragment,也可以移除fragment,用其他fragment代替当前fragment

简单例子

1.layout 目录中 创建一个fragment(如果是在Android studio中创建会自动生成 xml和Java文件),命名为: fragment_crime.xml , 重写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:layout_margin="16dp"
    android:orientation="vertical">
    
    <CheckBox
        android:id="@+id/crime_solved"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/crime_solved_label" />

</LinearLayout>

2. 自动生成的Java文件为 CrimeFragment.java,重写它

注意:
 1. fragment的视图并没有在 Fragment.onCreate(Bundle) 方法中生成
    创建和配置 fragment 视图是另一个 Fragment 生命周期方法完成的:onCreateView
    
 2. fragment的视图是直接通过调用 LayoutInflater.inflate(...) 方法并传入布局的资源ID生成的
     第一个参数:资源id
     第二个参数: 视图的父视图(不用改)
     第三个参数:告诉布局生成器是否将生成的视图添加给父视图
public class CrimeFragment extends Fragment {
    private CheckBox mSolvedCheckBox;

    // onCreate 生命周期 这里并不负责创建视图
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    // 这里负责创建视图并,还可以控制视图中的各种控件
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_crime, container, false);

        /* 这里为这个多选框设定一个选中事件,选中时 弹出吐司提示:你点击了多选框 */
        mSolvedCheckBox = (CheckBox)v.findViewById(R.id.crime_solved);
        mSolvedCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Toast.makeText(getContext(),"你点击了多选框",Toast.LENGTH_SHORT).show();
            }
        });

        return v;
    }
}

3. 处理 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">
    
    <!-- 新增的代码如下,这里创建了一个容器 -->
    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

4. 处理 MainActivity.java , 在 onCreate 生命周期函数中添加

// FragmentManager 类负责管理fragment并将它们的视图添加到 activity 的视图层级结构中
FragmentManager fm = getSupportFragmentManager();

// 创建一个新的fragment事务,执行一个fragment添加操作,然后提交该事务
// 也就是说 把 CrimeFragment对应的xml 填充进去 R.id.fragment_container 对应的 容器
fm.beginTransaction()
    .add(R.id.fragment_container, new CrimeFragment())
    .commit();

以此,fragment_crime.xml 中的代码将会代替 这个容器,包括 FragmentCrime.java 中定义的各种行为将会实现

5.
设备旋转或回收内存时,Android系统会销毁Activity,而后重建时,会调用onCreate(Bundle)方法,但是它的FragmentManager会将fragment队列保存下来这样,activity重建时,新的 FragmentManager会首先获取保存的队列,然后重建fragment队列,从而恢复到原来的状态,因此需要改进 4. 中的代码

// 获取一个fragment交给 FragmentManager 它管理 (第一次打开时的容器是空的,也就是 fragment == null)
Fragment fragment = fm.findFragmentById(R.id.fragment_container);

// 假如容器为空
if (fragment == null) {
    // “创建一个新的fragment事务,执行一个fragment添加操作,然后提交该事务
    // 也就是说 把 CrimeFragment对应的xml 填充进去 R.id.fragment_container 对应的 容器,这样该容器就不为null了
    fm.beginTransaction()
        .add(R.id.fragment_container, new CrimeFragment())
        .commit();
}

这样每次重建都会判断是否有存在的fragment队列,就不会反复创建了,直接从队列里取到。