Fragment的基本用法

一、Fragment简介

  • 碎片是一种可以嵌在Activity中的UI片段,是一个小型的Activity,又称Activity片段。
  • Fragment并不能单独使用,需要嵌套在Activity中使用。尽管它拥有自己的生命周期,但是还是会受到宿主Activity的生命周期的影响。

二、创建一个Fragment

1.静态加载Fragment

(1)创建Fragment布局文件
left_fragment.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">
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Button"/>
</LinearLayout>

right_fragment.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:background="#B9D6E3">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textSize="25sp"
        android:text="This is right Fragment"/>
</LinearLayout>

(2)自定义一个Fragment类,继承Fragment或者他的子类,重写onCreateView()方法 在该方法中调用:inflater.inflate()方法加载Fragment的布局文件,接着返回加载的view对象

public class LeftFragment extends Fragment {
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载布局
        View view = inflater.inflate(R.layout.left_fragment, container, false);
        return view;
    }
}
public class RightFragment extends Fragment {
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.right_fragment,container,false);
        return view;
    }
}

inflate(int resource, @Nullable ViewGroup root, boolean attachToRoot) :加载布局文件

  • 第一个参数:要加载的布局文件
  • 第二个参数:第一个参数的父布局
  • 第三个参数
    (1)true:表示将第一个参数表示的布局添加到第二个参数的布局中
    (2)false:不把第一个参数的布局添加到第二个参数的布局中

(3)在需要加载Fragment的Activity对应的布局文件中添加fragment的标签
activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/left_frag"
        android:name="com.example.fragmenttest.LeftFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>
    <fragment
        android:id="@+id/right_frag"
        android:name="com.example.fragmenttest.RightFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>
</LinearLayout>

<fragment>:在布局中添加碎片
android:name:要添加的碎片的类名,该类名为全限定类名

(4)Activity在onCreate( )方法中调用setContentView()加载布局文件即可
MainActivity.java文件不修改

2.动态加载Fragment

(1)创建Fragment布局文件
left_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#E696B1">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textSize="40sp"
        android:layout_marginLeft="20dp"
        android:textColor="#000000"
        android:text="这是本地视频"/>
</LinearLayout>

right_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#B9D6E3">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textSize="40sp"
        android:layout_marginLeft="20dp"
        android:textColor="#000000"
        android:text="这是网络视频"/>
</LinearLayout>

(2)自定义一个Fragment类,继承Fragment或者他的子类,重写onCreateView()方法 在该方法中调用:inflater.inflate()方法加载Fragment的布局文件,接着返回加载的view对象
代码同静态加载
(3)activity.main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/menu1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="本地视频"
            android:gravity="center"
            android:textSize="30sp"/>
        <TextView
            android:id="@+id/menu2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="网络视频"
            android:gravity="center"
            android:textSize="30sp"/>
    </LinearLayout>
    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"/>
</LinearLayout>

(4)MainActivity
获得FragementManager对象——>开启事务,获得FragmentTransaction对象
——>调用replace()方法添加碎片到容器——>提交事务

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView menu1;
    private TextView menu2;
    private FrameLayout content;
    private FragmentManager fragmentManager;
    private FragmentTransaction transaction;
    private Fragment fragment1;
    private Fragment fragment2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        //获得FragmentManager对象
        fragmentManager = getSupportFragmentManager();
        //开启事务,获得FragmentTransaction对象
        transaction = fragmentManager.beginTransaction();
        //创建需要添加的Fragment
        fragment1 = new LeftFragment();
        fragment2 = new RightFragment();
        //向容器内添加或替换碎片,默认情况下为LeftFragment
        transaction.replace(R.id.content,fragment1);
        //提交事务
        transaction.commit();
    }
    //初始化控件
    private void initView() {
        menu1 = (TextView)findViewById(R.id.menu1);
        menu2 = (TextView)findViewById(R.id.menu2);
        content = (FrameLayout) findViewById(R.id.content);
        menu1.setOnClickListener(this);
        menu2.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        transaction = fragmentManager.beginTransaction();
        switch (view.getId()){
            case R.id.menu1:
                //点击menu1,内容替换为leftFragment
                transaction.replace(R.id.content,fragment1);
                break;
            case R.id.menu2:
                //点击menu1,内容替换为RightFragment
                transaction.replace(R.id.content,fragment2);
                break;
            default:
                break;
        }
        transaction.commit();
    }
}

注意:

FragmentTransaction只能使用一次,每次使用都要调用FragmentManager
的beginTransaction()方法获得FragmentTransaction事务对象

方法详解:
getSupportFragmentManager():获得FragmentManager
beginTransaction():开启事务,获得FragmentTransaction对象
replace(int containerViewId, Fragment fragment):向容器内添加碎片
commit():提交事务

  • 第一个参数:要添加Fragment的容器
  • 第二个参数:添加的Fragment实例

运行样式:
通过点击不同TextView得到不同Fragment
点击本地视频:
在这里插入图片描述
点击网络视频:
请添加图片描述

三、碎片和活动之间进行通信

在这里插入图片描述

1.组件获取

(1)Fragment获取Activity中的组件:
通过getActivity()方法得到和当前碎片相关联的活动。再通过findViewById()获取Activity中相应组件
getActivity().findViewById(R.id.list)

碎片中使用Context对象,可通过getActivity()方法获取

(2)Activity获取Fragment中的组件:
通过getFragmentManager()方法得到FragmentManager。调用FragmentManager的findFragmentById()方法得到碎片的实例
getFragmentManager().findFragmentById(R.id.right_fragment)

2.数据传递

(1)Activity传递数据给Fragment
在上一个例子的基础上修改代码:
right_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#B9D6E3">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="20dp"
        android:textSize="40sp"
        android:textColor="#000000"
        android:text="这是网络视频" />
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        android:textSize="30sp"/>
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:layout_marginTop="10dp"
        android:layout_gravity="center"/>
</LinearLayout>

修改MainActivity代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
       ...
        transaction.replace(R.id.content,fragment1);
        //创建Bundle对象
        Bundle bundle = new Bundle();
        //向Bundle对象中添加数据
        bundle.putString("message","视频加载中....");
        //把数据设置到Fragment中
        fragment2.setArguments(bundle);
        transaction.replace(R.id.content,fragment1);
        //提交事务
        transaction.commit();
    }
    //初始化控件
    private void initView() {
      ...
    }
    @Override
    public void onClick(View view) {
        ...
}

修改RightFragment代码如下:

public class RightFragment extends Fragment {
    private Button button;
    private TextView text;
    private Bundle bundle;
    private String message;
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.right_fragment,container,false);
        button = view.findViewById(R.id.button1);
        text = view.findViewById(R.id.text);
        //获取从Activity传来的数据
        bundle = this.getArguments();
        //获取某一值
        message = bundle.getString("message");
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //显示传递过来的值
                text.setText(message);
            }
        });
        return view;
    }
}

方法详解:
setArguments(Bundle args):用于传递参数到Fragment,要传递的参数存放到Bundle对象中。
getArguments():获取Activity中传来的数据。返回值为Bundle对象。

运行样式:
没点击按钮之前网络视频页面:
a
点击按钮接收Activity传来的消息,网络视频页面:
请添加图片描述
(2)Fragment传递数据给Activity

(1)编写布局文件
my_fragment.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#E696B1">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginLeft="20dp"
        android:textColor="#000000"
        android:text="这是Fragment"
        android:textSize="40sp"/>
</LinearLayout>

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textSize="30sp"
        android:textColor="#000000"/>
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Button"/>
    <FrameLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"/>
</LinearLayout>

(2)设置回调接口,该接口用于用于Activity与Fragment通信

/*
    回调接口,用于Fragment和Activity之间通信
 */
public interface ICallBack {
    void getMessage(String message);
}

(3)自定义Fragment,设置接口回调方法

public class MyFragment extends Fragment {
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //加载布局
        View view = inflater.inflate(R.layout.left_fragment, container, false);
        return view;
    }
    //设置接口回调方法
    public void sendMessage(ICallBack callBack){
        callBack.getMessage("来自Fragment的消息");
    }
}

(4)MainActivity中调用接口回调方法

public class MainActivity extends AppCompatActivity {
    private TextView text;
    private Button button;
    private FragmentManager fragmentManager;
    private FragmentTransaction transaction;
    private MyFragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        fragmentManager = getSupportFragmentManager();
        transaction = fragmentManager.beginTransaction();
        fragment = new MyFragment();
        transaction.replace(R.id.content, fragment);
        transaction.commit();
    }
    private void initView() {
        text = (TextView) findViewById(R.id.text);
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 通过接口回调将消息从fragment发送到Activity
                fragment.sendMessage(new ICallBack() {
                    @Override
                    public void getMessage(String message) {
                        text.setText(message);
                    }
                });
            }
        });
    }
}

(3)Fragment和Fragment直接互相传递数据

FragmentManager fManager = getSupportFragmentManager( );
FragmentTransaction fTransaction = fManager.beginTransaction();
Fragmentone t1 = new Fragmentone();
Fragmenttwo t2 = new Fragmenttwo();
Bundle bundle = new Bundle();
bundle.putString("key",id);
t2.setArguments(bundle); 
fTransaction.add(R.id.content, t2);  
fTransaction.addToBackStack(t1);  
fTransaction.commit(); 

addToBackStack(String name):添加一个事务到返回栈

四、碎片的生命周期

1.碎片的四种状态

(1)运行状态:
当一个碎片是可见的,且它关联的活动处于运行状态时,该碎片也处于运行状态
(2)暂停状态:
一个活动进入暂停状态,与它相关联的碎片就会进入暂停状态
(3)停止状态:

  • 一个活动进入停止状态,与它相关联的碎片就会进入到停止状态
  • 调用FragmentTransaction的remove()、replace()移除或替换活动中的碎片,且在事务提交之前调用addToBackStack()方法,碎片会进入停止状态

(4)销毁状态:

  • 活动被销毁,与它相关联的碎片进行销毁状态
  • 调用FragmentTransaction的remove()、replace()移除或替换活动中的碎片,碎片进入销毁状态。

2.碎片的生命周期

在这里插入图片描述
onAttach():Fragment被添加到Activity中会调用
onCreateView():当Fragment创建视图(加载布局)时调用
onActivityCreated():Fragment关联的Activity创建完毕时调用
onDestoryView():与碎片关联的视图被移除的时候调用
onDetach():当碎片与活动解除关联关系的时候调用

实例:
点击LeftFragment界面的Button按钮,RightFragment被替换为AnotherRightFragment,观察整个过程中RightFragment的生命周期:
重要代码:
activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <fragment
       android:id="@+id/left_content"
       android:name="com.example.fragmenttest.LeftFragment"
       android:layout_width="0dp"
       android:layout_height="match_parent"
       android:layout_weight="1"/>
    <FrameLayout
        android:id="@+id/right_content"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>
</LinearLayout>

RightFragment.java

public class RightFragment extends Fragment {
    public static final String TAG = "RightFragment";
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        Log.d(TAG,"onAttach");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG,"onCreate");
    }
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG,"onCreateView");
        View view = inflater.inflate(R.layout.right_fragment,container,false);
        return view;
    }
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG,"onActivityCreated");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG,"onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG,"onResume");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG,"onPause");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG,"onStop");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(TAG,"onDestoryView");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestory");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG,"onDetach");
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private FragmentManager fragmentManager;
    private FragmentTransaction transaction;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);
        replaceFragment(new RightFragment());
    }
    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.button:
                replaceFragment(new AnotherRightFragment());
                break;
            default:
                break;
        }
    }
    public void replaceFragment(Fragment fragment){
        fragmentManager = getSupportFragmentManager();
        transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.right_content, fragment);
        transaction.commit();
    }
}

打印结果:
(1)RightFragment第一次被加载,依次执行:
onAttach()、onCreate()、onCreateView()、onActivityCreated()、onStart()、onResume()
(2)点击Button按钮,AnotherRightFragment替换了RightFragment。RightFragment被销毁,依次执行:
onPause()、onStop()、onDestoryView()、onDestory()、onDetch()
(3)按下Back键,RightFragment会重新回到屏幕,依次执行;
onAttach()、onCreate()、onCreateView()、onActivityCreated()、onStart()、onResume()
(4)再按Back键会退出程序,依次执行:
onPause()、onStop()、onDestoryView()、onDestory()、onDetch()

如果息屏:执行onPause()、onStop()方法;
再摁亮屏幕:执行onStart()、pnResume()方法

修改MainActivity.java的代码如下:

 public void replaceFragment(Fragment fragment){
        fragmentManager = getSupportFragmentManager();
        transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.right_content, fragment);
        //将事务添加到返回栈中
        transaction.addToBackStack(null);
        transaction.commit();
    }

打印结果:
(1)RightFragment第一次被加载,依次执行
onAttach()、onCreate()、onCreateView()、onActivityCreated()、onStart()、onResume()
(2)点击Button按钮,AnotherRightFragment替换了RightFragment。RightFragment进入停止状态,依次执行
onPause()、onStop()、onDestoryView()
(3)按下Back键,RightFragment会重新回到屏幕,依次执行;
onCreateView()、onActivityCreated()、onStart()、onResume()

因为RightFragment没有被销毁,只是进入停止状态了。所以重新回到运行状态不会执行onCreate()

(4)再按Back键,RightFragment界面消失,依次执行
onPause()、onStop()、onDestoryView()、onDestory()、onDetch()
(5)再按Back,退出程序
不执行什么方法了