Android中的碎片

使用的工具

现在android项目使用的 android studio 来进行开发,开发的语言现在推荐的是 kotlin, 不过这里还是先使用 Java 来开发

  • AndroidStudio 版本: Android Studio Iguana | 2023.2.1
  • 项目语言: Java
  • JDK版本: 17

什么是碎片

在讲解碎片之前需要先了解布局和控件,下面是一个布局文件的内容

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="horizontal"  
    android:layout_weight=""  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <!--  
        android:id="@+id/button_1" 表示给该控件添加了一个id  
        layout_width=match_parent 表示该button控件的宽度和父组件一致  
        layout_height=wrap_content 表示该button控件的高度是按照实际内容来的  
        android:text="ButtonOne" 是button中显示的内容  
    -->  
    <Button  
        android:id="@+id/second_activity_button_1"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="SecondActivityButtonOne"/>  
</LinearLayout>

  • 对于 LinearLayout 标签就是一个布局,对于更多的布局可以参考 [[06-Android开发中常用布局]]
  • 对于 Button 标签就是一个控件,就是表示一个按钮 接下来就来了解碎片了,现阶段先简单理解碎片就是在一个布局文件中添加另外一个布局文件,需要关注两部分内容
  • 在布局文件中通过 <fragment> 标签来引入一个碎片类,碎片类就是继承了 Fragment 的类
  • 在自定义的碎片类中可以加载另外一个布局文件

碎片代码示例

先看一下项目的整体结构在这里插入图片描述

  • MainActivity 类是主 Activity,该 Activity 对应的布局文件是 activity_main.xml, 该布局文件中有一个 Button MainActivity 类代码
package com.example.ademo;  
  
import android.content.Intent;  
import android.os.Bundle;  
import android.util.Log;  
import android.view.View;  
import android.widget.Button;  
  
import androidx.activity.EdgeToEdge;  
import androidx.annotation.Nullable;  
import androidx.appcompat.app.AppCompatActivity;  
  
public class MainActivity extends AppCompatActivity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        Log.d("MainActivity", "开始创建主Activity" + this);  
        super.onCreate(savedInstanceState);  
        //EdgeToEdge.enable(this);  
        setContentView(R.layout.activity_main);  
        // 通过 findViewById 方法获取 Button 实例  
        Button button = (Button)findViewById(R.id.cus_button);  
        // 给 button 设置点击监听器  
        button.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                startActivity(new Intent(MainActivity.this, FragmentMainActivity.class));  
            }  
        });  
    }   
}

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:id="@+id/main"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context=".MainActivity">  
  
    <Button  
        android:id="@+id/cus_button"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="MainActivityButton"  
        tools:ignore="MissingConstraints"></Button>  
</androidx.constraintlayout.widget.ConstraintLayout>

  • 点击 MainActivity 中的 Button 就会跳转到 FragmentMainActivity,FragmentMainActivity 对应的布局文件是 activity_fragment_main.xml FragmentMainActivity 类代码
package com.example.ademo;  
  
import android.os.Bundle;  
  
import androidx.activity.EdgeToEdge;  
import androidx.appcompat.app.AppCompatActivity;  
import androidx.core.graphics.Insets;  
import androidx.core.view.ViewCompat;  
import androidx.core.view.WindowInsetsCompat;  
  
public class FragmentMainActivity extends AppCompatActivity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_fragment_main);  
    }  
}

activity_fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="horizontal"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <!--layout_weight 占比的权重,现在只有两个控件,权重比是1:1,说明这两个控件是各占一半的空间-->  
    <fragment  
        android:id="@+id/fragment_main_one"  
        android:layout_width="0dp"  
        android:name="com.example.ademo.LeftFragment"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"></fragment>  
    <fragment  
        android:id="@+id/fragment_main_two"  
        android:name="com.example.ademo.RightFragment"  
        android:layout_width="0dp"  
        android:layout_height="wrap_content"  
        android:layout_weight="1"></fragment>  
</LinearLayout>

  • 在 activity_fragment_main.xml 布局文件中是使用 <fragment> 标签绑定了两个碎片,对应的类是 LeftFragment 和 RightFragment LeftFragment 类
package com.example.ademo;  
  
import android.os.Bundle;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
  
import androidx.fragment.app.Fragment;  
  
public class LeftFragment extends Fragment {  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                             Bundle savedInstanceState) {  
        // Inflate the layout for this fragment  
        return inflater.inflate(R.layout.fragment_left, container, false);  
    }  
}

RightFragment 类

package com.example.ademo;  
  
import android.os.Bundle;  
  
import androidx.fragment.app.Fragment;  
  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
  
public class RightFragment extends Fragment {  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                             Bundle savedInstanceState) {  
        // Inflate the layout for this fragment  
        return inflater.inflate(R.layout.fragment_right, container, false);  
    }  
}

这两个碎片类只是绑定了各自的布局文件而已 fragment_left.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="#00ff00"  
    android:orientation="vertical">  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_gravity="center_horizontal"  
        android:text="hello_blank_fragment left"  
        android:textSize="20sp" />  
  
</LinearLayout>

fragment_right.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:background="#ffffff"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text= "hello_blank_fragment right" />  
  
</LinearLayout>

动态添加碎片

对于动态添加碎片需要关注的内容 Fragment 类,即所有的碎片都需要继承 Fragment 类 FramentLayout, 这种布局一般都是配合 Fragment 来使用 FragmentManager 和 FragmentTransaction 下面看一下动态添加碎片的例子,如下图所示,一开始界面分成左右两部分,昨天有一个按钮和一个 TextView, 右侧就是一个 TextView, 当点击左侧的按钮之后动态替换到右侧的布局(右侧布局就是一个 Fragment) 在这里插入图片描述

项目结构

E:.
│  AndroidManifest.xml
│  
├─java
│  └─com
│      └─example
│          └─ademo
│              │  AnotherRightFragment.java
│              │  LeftFragment.java
│              │  MainActivity.java
│              │  RightFragment.java
└─res
    ├─layout
    │      activity_fragment_main.xml
    │      fragment_left.xml
    │      fragment_right.xml
    │      fragment_right_another.xml

  • 其实就是一个主 Activity(MainActivity) 和与其对应的布局文件(activity_fragment_main.xml)
  • 还有三个 Fragment 以及每一个 Fragment 对应的布局文件

MainActivity

public class MainActivity extends AppCompatActivity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        Log.d("MainActivity", "开始创建主Activity" + this);  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_fragment_main);  
        replaceFragment(new RightFragment());  
        Button button = findViewById(R.id.left_button);  
        button.setOnClickListener(v -> replaceFragment(new AnotherRightFragment()));  
    }  
  
    private void replaceFragment(Fragment rightFragment) {  
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_main_two, rightFragment).commit();  
    }  
}

activity_fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="horizontal"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <!--layout_weight 占比的权重,现在只有两个控件,权重比是1:1,说明这两个控件是各占一半的空间-->  
    <fragment  
        android:id="@+id/fragment_main_one"  
        android:layout_width="0dp"  
        android:name="com.example.ademo.LeftFragment"  
        android:layout_height="match_parent"  
        android:layout_weight="1"></fragment>  
    <FrameLayout  
        android:id="@+id/fragment_main_two"  
        android:layout_width="0dp"  
        android:layout_weight="1"  
        android:layout_height="match_parent"/>  
</LinearLayout>

因为右侧布局是需要动态替换的,所以使用 FrameLayout 布局

LeftFragment

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

fragment_left.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="#00ff00"  
    android:orientation="vertical">  
  
    <Button  
        android:id="@+id/left_button"  
        android:text="点我"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"/>  
      
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_gravity="center_horizontal"  
        android:background="@color/design_default_color_on_primary"  
        android:text="hello_blank_fragment left"  
        android:textSize="20sp" />  
  
</LinearLayout>

RightFragment

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

fragment_right.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:background="#ffffff"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:textColor="#000000"  
        android:text= "测试右边 right" />  
  
</LinearLayout>

AnotherRightFragment

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

fragment_right_another.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:background="#ffffff"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:background="@color/cardview_dark_background"  
        android:text= "hello_blank_fragment right another" />  
  
</LinearLayout>

从Activity中获取Fragment

从上面的例子中可以看到,Fragment 和 Activity 是分开的两个类,他们的布局文件也是分开的,那么如何在 Activity 中获取 Fragment 呢? 可以通过 FragmentManager.findFragmentById 方法来获取对应的 Fragment, getSupportFragmentManager 方法是在 FragmentActivity 中提供的

private void printFragment() {  
    FragmentManager fragmentManager = getSupportFragmentManager();  
    Fragment fragmentById = fragmentManager.findFragmentById(R.id.fragment_main_two);  
    Log.i("MainActivity", "fragmentById = " + fragmentById);  
}

在 Fragment中获取Activity

在 Fragment 中提供了 getActivity 方法来获取 Activity

碎片的生命周期

对于碎片的生命周期主要涉及到两个方面

  • 碎片的状态
  • 碎片的回调方法

碎片的状态

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

碎片的回调方法

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

如果你看到了这里,觉得文章写得不错就给个赞呗?
更多Android进阶指南 可以扫码 解锁更多Android进阶资料


在这里插入图片描述
敲代码不易,关注一下吧。ღ( ´・ᴗ・` )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值