Fragment的基本用法、Fragment和活动间的通信、Fragment的生命周期、动态加载布局的技巧

一、Fragment的简单用法

1、制作Fragment

1.1 新建一个布局文件left_fragment.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    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_horizontal"
        android:text="Button"/>


</LinearLayout>

1.2 新建一个LeftFragment类继承Fragment

java 复制代码
public class LeftFragment extends Fragment {

    LeftFragmentBinding binding;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        /**
         * 普通写法:
         *  View view = inflater.inflate(R.layout.left_fragment,container,false);
         *  retuen view;
         *  不需要重写onDestroyView
         */

        binding = LeftFragmentBinding.inflate(inflater,container,false);
         return binding.getRoot();
    }

    public void f(){
        Log.d("F","SSS");
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

重写onCreateView方法。

因为要保持binding的生命周期在有效范围内,所以需要在onDestroy中让binding=null

1.3 在布局文件activity_main.xml加载这个碎片

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/Leftfragment"
        android:name="com.example.fragment.LeftFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

</LinearLayout>

使用android:name指定加载的类,注意需要有完整的包名。

2、动态加载Fragment

2.1 新建一个用于替换的布局文件

新建一个用于替换的布局文件,another_left_fragment.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="#ffff00"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="24sp"
        android:text="This is Fragment"/>

</LinearLayout>

2.2 新建一个AnotherLeftFragment类继Fragment

java 复制代码
public class AnotherRightFragment  extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.another_right_fragment,container,false);
    }
}

3.3 在MainActivity中动态替换

java 复制代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener{

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


        //获取FragmentManager实例,通过向下转型为LeftFragment
        LeftFragment leftFragment = (LeftFragment) getSupportFragmentManager().findFragmentById(R.id.Leftfragment);

        //调用button按钮的监听器
        leftFragment.binding.Button.setOnClickListener(this);


    }


    @Override
    public void onClick(View view) {
        int Id = view.getId();
        if(Id == R.id.Button){

            /**
             * 匿名替换的方式:
             *  getSupportFragmentManager().beginTransaction().replace(R.id.Leftfragment,new AnotherRightFragment()).commit();
             */

            replaceFragment(new AnotherRightFragment());
        }
    }

    private void replaceFragment(Fragment fragment){
        //1、获取FragmentManager实例
        FragmentManager fragmentManager = getSupportFragmentManager();

        //2、开启一个事物
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        //3、向指定名称Id的容器内替换碎片实例
        transaction.replace(R.id.Leftfragment,fragment);

        //4、提交事物
        transaction.commit();

    }
}

3、在碎片中模拟返回栈

我们成功实现了向活动中动态添加碎片的功能,不过尝试一下就会发现,通过点击按钮添加了一个碎片之后,这时按下Back键程序就会直接退出。如果这里我们想模仿类似于返回栈的效果,按下Bck键可以回到上一个碎片,该如何实现呢?其实很简单FragmentTransaction中提供了一个addToBackStack()方法,可以用于将一个事务添加到返回栈中,修改MainActivity中的代码,如下所示:

java 复制代码
private void replaceFragment(Fragment fragment){
    //获取FragmentManager实例
    FragmentManager fragmentManager = getSupportFragmentManager();

    //开启一个事物
    FragmentTransaction transaction = fragmentManager.beginTransaction();

    //向指定名称Id的容器内替换碎片实例
    transaction.replace(R.id.Rightfragment,fragment);

    //添加返回栈
    transaction.addToBackStack(null);

    //提交事物
    transaction.commit();

}

4、Fragment和活动间的通信

4.1 从Activit中获取Fragment

其实我们已经用过很多次了,就是先获取LeftFragment的实例,如何通过实例中的binding访问Button的行为,这就是获取一个碎片,如何调用碎片中的方法。

java 复制代码
        //获取FragmentManager实例,通过向下转型为LeftFragment
        LeftFragment leftFragment = (LeftFragment) getSupportFragmentManager().findFragmentById(R.id.Leftfragment);

4.2 从Fragment中获得Activit

使用getActivit即可,因为获得的活动本身就是一个Context对象

java 复制代码
MainActivit activit = (MainActivit) getActivit();

二、Fragment的生命周期

1、Fragment的四种状态和回调

状态:

  • 运行状态:当一个碎片是可见的,并且它所关联的活动正处于运行状态时,该碎片也处于运行状态。
  • 暂停状态:当一个活动进人暂停状态时(由于另一个未占满屏幕的活动被添加到了栈顶),与它相关联的可见碎片就会进人到暂停状态。
  • 停止状态:当一个活动进入停止状态时,与它相关联的碎片就会进入到停止状态,或者通过调用FragmentTransactionremove()replace()方法将碎片从活动中移除,但如果在事务提交之前调用addToBackStack()方法,这时的碎片也会进入到停止状态。
  • 销毁状态:碎片总是依附于活动而存在的,因此当活动被销毁时,与它相关联的碎片就会进人到销毁状态。或者通过调用FragmentTransaction的remove()、replace()方法将碎片从活动中移除,但在事务提交之前并没有调用addToBackStack()方法,这时的碎片也会进人到销毁状态。

回调方法:

  • onAttach():当活动和碎片建立关联时使用
  • OnCreateView:当为碎片创建视图时使用
  • onActivityCreated():确保与碎片相关联的活动一定已经创建完毕的时候调用。
  • onDestroyView()。当与碎片关联的视图被移除的时候调用。
  • onDetach()。当碎片和活动解除关联的时候调用。

2、Fragment的生命周期

旧版生命周期如下:

打开一个碎片生命周期的调用情况:

一般**onCreateView()**用于初始化Fragment的视图,**onViewCreated()一般用于初始化视图内各个控件,而onCreate()**用于初始化与Fragment视图无关的变量。

另外值得一提的是,在碎片中你也是可以通过onSaveInstanceState()方法来保存数据的,因为进入停止状态的碎片有可能在系统内存不足的时候被回收。保存下来的数据在onCreate()onCreateview()onActivityCreated()这3个方法中你都可以重新得到,它们都含有一个Bundle类型的savedInstanceState参数。

三、动态加载布局的技巧

1、使用限定符

Android Studio中res下创建layout-large

版本:Android Studio Flamingo | 2022.2.1 Patch 2

在res右键Android resource file,resource type选择layout,available qualifiers选择Size,在右侧chosen qualifiers选择large,最后输入file name,新建成功,这样在res目录下自动新建layout-large文件夹,并在文件夹中生成刚输入的file name的布局文件

常见限定符参考表:

2、使用最小限定符

最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以中为单位),然后以这个最小值为临界点,屏幕宽度大于这个值的设备就加载一个布局,屏幕宽度小于这个值的设备就加载另一个布局。

这就意味着,当程序运行在屏幕宽度大于600dp的设备上时,会加载layout--sw600 dp/activity main布局,当程序运行在屏幕宽度小于600dp的设备上时,则仍然加载默认的layout/activity main布局。

相关推荐
华仔啊1 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang1 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang2 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解3 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
砖厂小工5 小时前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
张拭心5 小时前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心5 小时前
Android 17 来了!新特性介绍与适配建议
android·前端
SimonKing7 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean7 小时前
Jackson View Extension Spring Boot Starter
java·后端
Kapaseker8 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin