使用的工具
现在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进阶资料
敲代码不易,关注一下吧。ღ( ´・ᴗ・` )