当前位置: 首页 > news >正文

掌握Android Fragment开发之魂:Fragment的深度解析(上)


Fragment是Android开发中用于构建动态和灵活界面的基石。它不仅提升了应用的模块化程度,还增强了用户界面的动态性和交互性,允许开发者将应用界面划分为多个独立、可重用的部分,每个部分都可以独立于其他部分进行操作。本文将从以下几个方面深入探讨Fragment的核心特性、优势、生命周期,以及如何通过静态和动态添加来丰富你的应用。


一、Fragment的特点


Fragment是Android中非常强大和灵活的概念,它极大地简化了构建动态和可适应不同屏幕尺寸的复杂UI的过程。通过合理利用Fragment,您可以构建模块化、可重用和高效的Android应用程序。


以下是Fragment的一些主要特点:

  1. 模块化UI: Fragment允许您将UI分解为独立的模块化组件。每个Fragment都定义了自己的布局和行为,并且可以在活动中添加、删除或替换。这使得构建可重用的UI组件和适应不同屏幕尺寸变得更加容易。

  2. 生命周期管理: 与Activity类似,Fragment也有自己的生命周期。系统负责管理Fragment的生命周期,使您能够专注于编写代码而不必担心生命周期问题。Fragment的生命周期回调与Activity的生命周期回调类似,但Fragment的生命周期优先于托管它的Activity。

  3. 向后兼容性: 在旧版本的Android系统上,Fragment提供了一种模拟新UI模式的方法。即使在较旧的Android版本上,您也可以编写支持片段的应用程序。

  4. 动态UI: Fragment可以在运行时动态添加到Activity布局中。这为您提供了灵活性,可以根据不同的条件动态构建和改变UI。

  5. 嵌套Fragment: Fragment可以嵌套在另一个Fragment中,这为构建复杂的UI层次结构提供了极大的灵活性。

  6. 支持多窗格设计: Fragment非常适合在大屏幕设备(如平板电脑)上实现多窗格UI设计。您可以将不同的Fragment组合在一个Activity中,并根据设备方向和大小调整布局。

  7. 提高可重用性: Fragment可以在多个Activity之间共享和重用。这不仅提高了代码的可重用性,还减少了代码重复,从而提高了应用程序的可维护性。

  8. Fragment事务: Fragment事务允许您在Activity布局中添加、移除、替换和附加Fragment。您可以通过提交一系列Fragment事务来构建复杂的UI流程。

  9. 支持RetainInstance: Fragment可以在配置更改(如设备旋转)时保留其实例。这意味着您可以避免重新创建昂贵的对象,从而提高应用程序的性能和响应能力。

  10. 向后兼容库支持: Android提供了对旧版本系统的Fragment向后兼容库支持。即使在较旧的Android版本上,您也可以使用Fragment提供的大多数功能。


二、Fragment的生命周期

在这里插入图片描述


Fragment的生命周期与Activity紧密相关,但有自己的特点。了解Fragment的生命周期对于正确管理Fragment至关重要。

Android Fragment拥有自己的生命周期,类似于Activity的生命周期。Fragment的生命周期回调方法与Activity非常相似,但又有一些独特之处。下面是Fragment生命周期的详细介绍,并通过Java代码示例进行演示:


1、onAttach(Context)

当Fragment与Activity实例关联时调用。可以在此方法中获取Activity的引用,并执行一些初始化操作。

@Override
public void onAttach(@NonNull Context context) {super.onAttach(context);// 获取Activity引用并执行初始化操作
}

2、onCreate(Bundle)

在Fragment创建时调用。可以在此方法中初始化一些数据和状态。

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 初始化数据和状态
}

3、onCreateView(LayoutInflater, ViewGroup, Bundle)

创建并返回Fragment的视图层次结构。

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_layout, container, false);// 初始化视图return view;
}

4、onViewCreated(View, Bundle)

在Fragment的视图层次结构创建完成后调用。可以在此方法中进行视图的初始化操作。

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);// 初始化视图
}

5、onActivityCreated(Bundle)

在Activity的onCreate方法执行完毕后调用。

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);// 执行一些与Activity相关的操作
}

6、onStart()

当Fragment变为可见状态时调用


7、onResume()

当Fragment开始交互时调用。


8、onPause()

当Fragment从交互状态切换到暂停状态时调用。可以在此方法中释放一些资源。


9、onStop()

当Fragment不再可见时调用。


10、onDestroyView()

在Fragment的视图层次结构被销毁时调用。


11、onDestroy()

在Fragment被销毁之前调用。可以在此方法中释放资源。


12、onDetach()

当Fragment与Activity实例分离时调用。


此外,Fragment还提供了一些额外的生命周期回调方法,用于处理保存和恢复实例状态:

13、onSaveInstanceState(Bundle)

当Fragment需要保存状态时调用。可以在此方法中保存数据。

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);// 保存数据
}

14、onViewStateRestored(Bundle)

在Fragment视图状态被恢复后调用。可以在此方法中恢复数据。

@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {super.onViewStateRestored(savedInstanceState);// 恢复数据
}

三、Fragment的使用方式


在 Android 应用程序中使用 Fragment 有几种常见的方式,包括静态添加、动态添加和使用 FragmentManager 进行事务管理。下面通过 Java 代码示例演示每种方式:


1、静态添加 Fragment


静态添加 Fragment 是指在 Activity 的布局文件中直接定义 Fragment。这种方式适用于在应用启动时就需要显示的 Fragment。


(1)、 创建Fragment布局文件

首先,我们需要为每个Fragment创建一个布局文件。

fragment_a.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:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment A"android:textSize="24sp" /><Buttonandroid:id="@+id/btn_fragment_a"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Click Me" /></LinearLayout>
fragment_b.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:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment B"android:textSize="24sp" /><Buttonandroid:id="@+id/btn_fragment_b"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Click Me" /></LinearLayout>

(2)、 创建Fragment类


接下来,我们需要创建两个Fragment类,每个类对应一个Fragment布局。

FragmentA.java
public class FragmentA extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_a, container, false);Button btnFragmentA = view.findViewById(R.id.btn_fragment_a);btnFragmentA.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 处理按钮点击事件Toast.makeText(getActivity(), "Fragment A Button Clicked", Toast.LENGTH_SHORT).show();}});return view;}
}
FragmentB.java
public class FragmentB extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_b, container, false);Button btnFragmentB = view.findViewById(R.id.btn_fragment_b);btnFragmentB.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 处理按钮点击事件Toast.makeText(getActivity(), "Fragment B Button Clicked", Toast.LENGTH_SHORT).show();}});return view;}
}

(3)、 在Activity布局中静态添加Fragment

现在,我们将在Activity的布局文件中静态添加两个Fragment。

activity_main.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:orientation="horizontal"><fragmentandroid:id="@+id/fragment_a"android:name="com.example.FragmentA"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" /><fragmentandroid:id="@+id/fragment_b"android:name="com.example.FragmentB"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" /></LinearLayout>

在上面的布局文件中,我们使用<fragment>标签来静态添加两个Fragment。android:name属性指定了Fragment的完全限定类名,android:id属性为每个Fragment提供了一个唯一的标识符。


(4)、MainActivity

最后,我们只需要创建一个空的MainActivity即可,因为所有的Fragment都已经在布局文件中静态添加了。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}

当你运行这个应用程序时,你会看到两个Fragment并排显示在屏幕上,每个Fragment中都有一个按钮。点击这些按钮会显示相应的Toast消息。


静态添加Fragment是一种简单而直接的方式,适用于在应用启动时就需要显示Fragment的情况。但是,如果你需要动态添加、移除或替换Fragment,那么你需要使用FragmentManager来管理Fragment事务。


2、动态添加 Fragment

动态添加 Fragment 是指在运行时通过代码将 Fragment 添加到 Activity 的布局中。这种方式适用于根据用户交互或其他条件动态显示 Fragment。

我们将创建一个主Activity,其布局文件中包含一个容器用于显示Fragment。我们将定义两个Fragment,并使用FragmentManager在容器中进行Fragment的添加、替换和移除操作。

(1)、 创建Fragment布局文件

首先,我们需要为每个Fragment创建一个布局文件。

fragment_a.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:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment A"android:textSize="24sp" /></LinearLayout>
fragment_b.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:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment B"android:textSize="24sp" /></LinearLayout>

(2)、创建Fragment类

接下来,我们需要创建两个Fragment类,每个类对应一个Fragment布局。

FragmentA.java
public class FragmentA extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_a, container, false);}
}
FragmentB.java
public class FragmentB extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_b, container, false);}
}

(3)、创建Activity布局

接下来,我们将创建Activity的布局文件,其中包含一个容器用于显示Fragment,以及四个按钮用于控制Fragment的添加、替换和移除操作。

activity_main.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:orientation="vertical"><FrameLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_add_fragment_a"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Add Fragment A" /><Buttonandroid:id="@+id/btn_replace_fragment_b"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Replace with Fragment B" /><Buttonandroid:id="@+id/btn_remove_fragment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Remove Fragment" /><Buttonandroid:id="@+id/btn_attach_fragment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Attach Fragment" /></LinearLayout></LinearLayout>

在上面的布局文件中,我们使用<FrameLayout>作为容器来显示Fragment。下面的<LinearLayout>中包含四个按钮,分别用于添加FragmentA、替换为FragmentB、移除当前Fragment和附加Fragment。


(4)、 MainActivity

最后,我们将创建MainActivity并实现按钮的点击事件,用于动态添加和移除Fragment。

public class MainActivity extends AppCompatActivity {private FragmentManager fragmentManager;private FrameLayout fragmentContainer;private FragmentA fragmentA;private FragmentB fragmentB;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fragmentManager = getSupportFragmentManager();fragmentContainer = findViewById(R.id.fragment_container);Button btnAddFragmentA = findViewById(R.id.btn_add_fragment_a);btnAddFragmentA.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {addFragment(new FragmentA());}});Button btnReplaceFragmentB = findViewById(R.id.btn_replace_fragment_b);btnReplaceFragmentB.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {replaceFragment(new FragmentB());}});Button btnRemoveFragment = findViewById(R.id.btn_remove_fragment);btnRemoveFragment.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {removeFragment();}});Button btnAttachFragment = findViewById(R.id.btn_attach_fragment);btnAttachFragment.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {attachFragment();}});// 初始化并添加 FragmentAfragmentA = new FragmentA();addFragment(fragmentA);}private void addFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();}private void replaceFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();}private void removeFragment() {Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);if (fragment != null) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.remove(fragment);transaction.commit();}}private void attachFragment() {if (fragmentB == null) {fragmentB = new FragmentB();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragmentB);transaction.detach(fragmentB);transaction.commit();} else {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.attach(fragmentB);transaction.commit();}}
}

MainActivity中,我们首先获取FragmentManager和容器FrameLayout的实例。然后,我们为三个按钮设置点击事件监听器。

  • "Add Fragment A"按钮会调用addFragment()方法,将FragmentA实例动态添加到容器中。
  • "Add Fragment B"按钮会调用addFragment()方法,将FragmentB实例动态添加到容器中。
  • "Remove Fragment"按钮会调用removeFragment()方法,移除当前容器中的Fragment。

addFragment()方法中,我们使用FragmentTransaction来添加Fragment。我们还调用了addToBackStack()方法,这样当用户按下返回键时,Fragment就会从容器中移除。

removeFragment()方法中,我们首先使用findFragmentById()方法获取当前容器中的Fragment实例。如果存在Fragment,我们就使用FragmentTransaction将其从容器中移除。


当你运行这个应用程序时,你会看到一个空白的容器和三个按钮。点击"Add Fragment A"或"Add Fragment B"按钮,相应的Fragment就会动态添加到容器中。点击"Remove Fragment"按钮,当前容器中的Fragment就会被移除。你还可以反复添加和移除Fragment,观察其行为。


3、使用 FragmentManager 管理 Fragment

FragmentManager 提供了一系列方法用于管理 Fragment 的生命周期和事务。我们可以使用它来添加、移除、替换和附加 Fragment。


public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取 FragmentManagerFragmentManager fragmentManager = getSupportFragmentManager();// 开启一个事务FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();// 替换 FragmentFragment fragmentA = new FragmentA();fragmentTransaction.replace(R.id.fragment_container, fragmentA);// 提交事务fragmentTransaction.commit();}
}

MainActivity中,我们首先获取FragmentManager和容器FrameLayout的实例,并初始化fragmentAfragmentB实例。


然后,我们为四个按钮设置点击事件监听器:

  • "Add Fragment A"按钮会调用addFragment()方法,将FragmentA实例添加到容器中。

  • "Replace with Fragment B"按钮会调用replaceFragment()方法,用FragmentB实例替换当前容器中的Fragment。

  • "Remove Fragment"按钮会调用removeFragment()方法,移除当前容器中的Fragment。

  • "Attach Fragment"按钮会调用attachFragment()方法,首次点击时会添加并分离FragmentB实例,之后点击则会重新附加该Fragment实例。


让我们逐一了解这些方法的实现:

首先,addFragment()方法

private void addFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();
}

这个方法使用FragmentTransaction来添加一个新的Fragment实例到容器中。我们调用add()方法来添加Fragment,并使用addToBackStack()方法将该事务添加到回退栈中,以便用户可以通过返回键来撤销该操作。


其次,replaceFragment()方法:

private void replaceFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();
}

这个方法使用FragmentTransaction将当前容器中的Fragment替换为一个新的Fragment实例。我们调用replace()方法来替换Fragment,并同样使用addToBackStack()方法将该事务添加到回退栈中。


然后,removeFragment()方法:

private void removeFragment() {Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);if (fragment != null) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.remove(fragment);transaction.commit();}
}

这个方法首先使用findFragmentById()方法获取当前容器中的Fragment实例。如果存在Fragment,我们就使用FragmentTransaction将其从容器中移除。


最后,attachFragment()方法:

private void attachFragment() {if (fragmentB == null) {fragmentB = new FragmentB();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragmentB);transaction.detach(fragmentB);transaction.commit();} else {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.attach(fragmentB);transaction.commit();}
}

这个方法用于演示detach()attach()方法的使用。首次点击"Attach Fragment"按钮时,我们会添加一个新的FragmentB实例,然后立即将其分离。之后再次点击该按钮时,我们会重新附加该Fragment实例。这种做法可以在不销毁Fragment的情况下临时隐藏它,从而保留其状态。


在上面的代码中,我们还在onCreate()方法中初始化并添加了FragmentA实例。

当你运行这个应用程序时,你会看到一个显示FragmentA的容器和四个按钮。你可以尝试点击不同的按钮,观察Fragment的添加、替换、移除和附加/分离操作。

通过这个案例,能够更好地理解如何使用FragmentManager来管理Fragment的生命周期和事务。FragmentManager提供了丰富的方法,如add()replace()remove()attach()detach()等,让你可以灵活地控制Fragment的行为。你还可以使用addToBackStack()方法将Fragment事务添加到回退栈中,从而实现类似Activity的导航行为。


结语:

通过本文的深入解析,你应该对Fragment有了更全面的理解。无论是在构建新的应用还是优化现有项目,Fragment都是你不可或缺的工具。Fragment的潜力远不止于此。

在下一篇文章中,我们将探索如何使用Fragment实现更高级的界面切换效果,以及如何在Fragment之间传递数据。敬请期待!


相关文章:

掌握Android Fragment开发之魂:Fragment的深度解析(上)

Fragment是Android开发中用于构建动态和灵活界面的基石。它不仅提升了应用的模块化程度&#xff0c;还增强了用户界面的动态性和交互性&#xff0c;允许开发者将应用界面划分为多个独立、可重用的部分&#xff0c;每个部分都可以独立于其他部分进行操作。本文将从以下几个方面深…...

深度解读DreamFusion:一站式AI解决方案

DreamFusion是一款备受瞩目的人工智能解决方案&#xff0c;它整合了多种AI技术&#xff0c;为用户提供了一站式的解决方案。本文将全面解读DreamFusion&#xff0c;探讨其特点、功能和应用场景&#xff0c;助您深入了解这一创新工具。 1. 特点概述 DreamFusion具备以下显著特…...

JVM-02

字节码文件是一种特殊的文件格式&#xff0c;它包含了将源代码转换为机器可执行代码所需的指令集。字节码文件通常是由编译器将源代码编译为字节码的中间表示形式。 在Java中&#xff0c;字节码文件的扩展名为.class&#xff0c;它存储了编译后的Java代码。这些字节码文件可以在…...

【一起深度学习——NIN】

NIN神经网络 原理图&#xff1a;代码实现&#xff1a;输出结果&#xff1a; 原理图&#xff1a; 代码实现&#xff1a; import torch from torch import nn from d2l import torch as d2ldef nin_block(in_channels, out_channels, kernel_size, strides, padding):return nn.…...

数字工厂管理系统如何助力企业数据采集与分析

随着科技的不断进步&#xff0c;数字化已成为企业发展的重要趋势。在制造业领域&#xff0c;数字工厂管理系统的应用日益广泛&#xff0c;它不仅提升了生产效率&#xff0c;更在数据采集与分析方面发挥着举足轻重的作用。本文旨在探讨数字工厂管理系统如何助力企业数据采集与分…...

uniap之微信公众号支付

近来用uniapp开发H5的时候&#xff0c;需要接入支付&#xff0c;原来都是基于后端框架来做的&#xff0c;所以可谓是一路坑中过&#xff0c;今天整理下大致流程分享给大家。 先封装util.js&#xff0c;便于后面调用 const isWechat function(){return String(navigator.userA…...

Django知识点总结

因为最近在搞一个Python项目&#xff0c;使用的Django框架。所以快速学习了一下这个web框架。并做一些总结。 Django官网的介绍&#xff1a;Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experience…...

算法(C++

题目&#xff1a;螺旋矩阵&#xff08;59. 螺旋矩阵 II - 力扣&#xff08;LeetCode&#xff09;&#xff09; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&am…...

Python专题:六、循环语句(1)

补充知识 代码的注释 #描述性文字 阅读代码的人更好的理解代码 while循环语句 x<100条件控制语句&#xff0c;Totalx,Total自增加x&#xff0c;x1&#xff0c;x自增加1&#xff0c;x<100此条件满足时&#xff0c;执行while循环&#xff0c;当x101时&#xff0c;x101条…...

力扣2105---给植物浇水II(Java、模拟、双指针)

题目描述&#xff1a; Alice 和 Bob 打算给花园里的 n 株植物浇水。植物排成一行&#xff0c;从左到右进行标记&#xff0c;编号从 0 到 n - 1 。其中&#xff0c;第 i 株植物的位置是 x i 。 每一株植物都需要浇特定量的水。Alice 和 Bob 每人有一个水罐&#xff0c;最初是…...

Windows设置Redis为开机自启动

前言 Redis作为当前最常用的当前缓存技术&#xff0c;基本上Web应用中都有使用。所以&#xff0c;每次我们在本地启动项目前&#xff0c;都必须将Redis服务端启动。但是&#xff0c;每次都要去启动Redis就很麻烦&#xff0c;有没有办法做到开机自动启动Redis呢&#xff1f;这当…...

行业早报5.10

1.鸿蒙智行 4 月交付 29632 辆蝉联中国新势力月销冠&#xff0c;问界 M9 超 13000 辆&#xff1b; 2.三星收购胎儿超声 AI 软件公司 Sonio&#xff0c;巩固尖端医疗设备领域的领先地位&#xff1b; 3.蔚来汽车 4 月交付 15620 辆新车&#xff0c;同比增长 134.6%&#xff1b; 4…...

Java+SpringBoot+JSP实现在线心理评测与咨询系统

前言介绍 随着互联网技术的高速发展&#xff0c;人们生活的各方面都受到互联网技术的影响。现在人们可以通过互联网技术就能实现不出家门就可以通过网络进行系统管理&#xff0c;交易等&#xff0c;而且过程简单、快捷。同样的&#xff0c;在人们的工作生活中&#xff0c;也就…...

机器学习算法应用——K近邻分类器(KNN)

K近邻分类器&#xff08;KNN&#xff09;&#xff08;4-2&#xff09; K近邻分类器&#xff08;K-Nearest Neighbor&#xff0c;简称KNN&#xff09;是一种基本的机器学习分类算法。它的工作原理是&#xff1a;在特征空间中&#xff0c;如果一个样本在特征空间中的K个最相邻的样…...

python数据分析——数据的选择和运算

数据的选择和运算 前言一、数据选择NumPy的数据选择一维数组元素提取示例 多维数组行列选择、区域选择示例 花式索引与布尔值索引布尔索引示例一示例二 花式索引示例一示例二 Pandas数据选择Series数据获取DataFrame数据获取列索引取值示例一示例二 取行方式示例loc() 方法示例…...

《CKA/CKAD应试指南/从docker到kubernetes 完全攻略》学习笔记 第8章 deployment

目录 前言 8.1创建和删除deployment 8.1.1通过yaml文件的方式创建deployment 8.1.2 deployment 健壮性测试...

步态识别论文(6)GaitDAN: Cross-view Gait Recognition via Adversarial Domain Adaptation

摘要: 视角变化导致步态外观存在显着差异。因此&#xff0c;识别跨视图场景中的步态是非常具有挑战性的。最近的方法要么在进行识别之前将步态从原始视图转换为目标视图&#xff0c;要么通过蛮力学习或解耦学习提取与相机视图无关的步态特征。然而&#xff0c;这些方法有许多约…...

K8S中的弹性云服务如何搭建,可能遇到的问题,如何解决!(稳啦!!!!全都稳啦!!!)

首先我们先来了解一下这玩意儿~~~ 啥是弹性云服务&#xff08;Elastic Cloud Service&#xff09;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 弹性云服务&#xff08;ECS&#xff09;是一种基于云计算技术的虚拟服务器&#xff0c;由vCPU、内存、磁盘等组成的获取方便…...

新增分类——后端

实现功能&#xff1a; 代码开发逻辑&#xff1a; 页面发送ajax请求&#xff0c;将新增分类窗口输入的数据以json形式提交到服务端服务端Controller接收页面提交的数据并调用Service将数据进行保存Service调用Mapper操作数据库&#xff0c;保存数据 代码实现&#xff1a; Con…...

20232801 2023-2024-2 《网络攻防实践》实践九报告

20232801 2023-2024-2 《网络攻防实践》实践九报告 1.实践内容 &#xff08;1&#xff09;手工修改可执行文件&#xff0c;改变程序执行流程&#xff0c;直接跳转到getShell函数。 &#xff08;2&#xff09;利用foo函数的Bof漏洞&#xff0c;构造一个攻击输入字符串&#xf…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...