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

安卓-碎片的使用入门

1.碎片(Fragment)是什么

Fragment是依赖于Activity的,不能独立存在的,是Activity界面中的一部分,可理解为模块化的Activity,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用得非常广泛.

  • Fragment不能独立存在,必须嵌入到Activity中
  • Fragment具有自己的生命周期,接收它自己的事件,并可以在Activity运行时被添加或删除
  • Fragment的生命周期直接受所在的Activity的影响。如:当Activity暂停时,它拥有的所有Fragment们都暂停

那么究竟要如何使用碎片才能充分地利用平板屏幕的空间呢?想象我们正在开发一个新闻应用,其中一个界面使用RecyclerView展示了一组新闻的标题,当点击了其中一个标题时,就打开另一个界面显示新闻的详细内容。如果是在手机中设计,我们可以将新闻标题列表放在一个活动中,将新闻的详细内容放在另一个活动中.

可是如果在平板上也这么设计,那么新闻标题列表将会被拉长至填充满整个平板的屏幕,而新闻的标题一般都不会太长,这样将会导致界面上有大量的空白区域.

因此,更好的设计方案是将新闻标题列表界面和新闻详细内容界面分别放在两个碎片中,然后在同一个活动里引入这两个碎片,这样就可以将屏幕空间充分地利用起来了.

2. 碎片的简单用法

这里我们准备先写一个最简单的碎片示例来练练手,在一个活动当中添加两个碎片,并让这两个碎片平分活动空间。

新建一个左侧碎片布局left_fragment.xml,代码如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="Button"/></LinearLayout>

这个布局非常简单,只放置了一个按钮,并让它水平居中显示。然后新建右侧碎片布局right_fragment.xml,代码如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:background="#00ff00"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:textSize="20sp"android:text="This is right fragment"/></LinearLayout>

可以看到,我们将这个布局的背景色设置成了绿色,并放置了一个TextView用于显示一段文本。

接着新建一个LeftFragment 类,并让它继承自Fragment,现在编写一下LeftFragment 中的代码

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 {public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View view = inflater.inflate(R.layout.left_frame, container, false);return view;}}

这里仅仅是重写了Fragment的onCreateView()方法,然后在这个方法中通过LayoutInflater的inflate()方法将刚才定义的left_fragment布局动态加载进活动中来,整个方法简单明了。

那么问题来了,上面所提到的,将自己对应的布局文件left_fragment.xml以及right_fragment.xml加载进来,那什么时候加载进来呢?这个问题在碎片布局的引入执行逻辑一章中再进行回答。

接着我们用同样的方法再新建一个RightFragment ,代码如下所示:

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import androidx.fragment.app.Fragment;public class RightFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View view = inflater.inflate(R.layout.right_fragment, container, false);return view;}}

基本上代码都是相同的,相信已经没有必要再做什么解释了。新版android怎么添加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" ><fragmentandroid:id="@+id/left_fragment"android:name="com.example.fragmenttest.LeftFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" tools:layout="@layout/left_fragment"/><fragmentandroid:id="@+id/right_fragment"android:name="com.example.fragmenttest.RightFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" tools:layout="@layout/right_fragment"/></LinearLayout>

可以看到,我们使用了<fragment>标签在布局中添加碎片,其中指定的大多数属性都是你熟悉的,只不过这里还需要通过android:name 属性来显式指明要添加的碎片类名,注意一定要将类的包名也加上(因为不加上就不知道此fragment标签是由哪一个类实现的),最后要加上tools:layout=""XXX"。 

运行结果:

 2.1 碎片布局引入活动的程序执行逻辑

 

现在可以回答上述问题了,究竟何时何地加载了两个碎片布局。由于我们在MainActivity方法中调用了方法:setContentView(R.layout.activity_main);所以只会加载布局文件activity_main.xml,而我们在此布局文件中添加了两个fragment控件,而实际上其通过:android:name="com.example.fragmenttest.LeftFragment"指向了类文件:LeftFragment.java,(我们不是通过android:id="@+id/left_fragment"知道这个碎片控件实现类是谁,而是android:name来控制的),而类文件LeftFragment.java则重写了方法onCreateView(),使其返回一个我们所指定的的布局View对象,而这个对象是由R.layout.left_fragment指向了:left_fragment.xml。

所以执行逻辑可以认为是大致如下:

MainActivity#onCreate -> activity_main.xml -> <fragment>-> <fragment>标签中的android:name -> LeftFragment类 ->LayoutInflater#inflate(int, android.view.ViewGroup, boolean)方法 -> left_fragment.xml -> right_fragment同理。

 可以发现实际上上述代码执行顺序和我们写代码的顺序是完全相反的,我们首先要写一个关于fragment的布局xml文件,接着创建一个碎片类去引用这个布局文件,最后第二步是在activity_main文件中通过android:name来引用这个碎片类,最后才是在MainActivity中加载activity_main布局。可以说这样写代码的好处是不会IDE是不会报错引用错误,坏处是和程序的执行顺序正好相反,但是如果你深谙代码的执行逻辑,首先就是在activity_main文件中通过android:name来引用这个碎片类,一步步你想思维,我想可能也是一个写Android代码的好思维方式。

3.动态添加碎片

在上一节当中,你已经学会了在布局文件中添加碎片的方法,不过碎片真正的强大之处在于,它可以在程序运行时动态地添加到活动当中。根据具体情况来动态地添加碎片,你就可以将程序界面定制得更加多样化。

我们还是在上一节代码的基础上继续完善,新建another_right_fragment.xml,代码如下

<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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:textSize="20sp"android:text="This is another right fragment"/></LinearLayout>

 这个布局文件的代码和right_fragment.xml中的代码基本相同,只是将背景色改成了黄色,并将显示的文字改了改。然后新建AnotherRightFragment 作为另一个右侧碎片,代码如下

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import androidx.fragment.app.Fragment;public class AnotherRightFragment extends Fragment {public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View view = inflater.inflate(R.layout.another_right_fragment, container, false);return view;}
}

代码同样非常简单,在onCreateView() 方法中加载了刚刚创建的another_right_fragment布局。这样我们就准备好了另一个碎片,接下来看一下如何将它动态地添加到活动当中。修改activity_main.xml,代码如下

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:orientation="horizontal"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent" ><androidx.fragment.app.FragmentContainerViewandroid:id="@+id/fragmentContainerView"android:name="com.example.myapplication.LeftFragment"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"tools:layout="@layout/left_fragment" /><FrameLayoutandroid:id="@+id/right_layout"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" ></FrameLayout><!--    <androidx.fragment.app.FragmentContainerView-->
<!--        android:id="@+id/fragmentContainerView2"-->
<!--        android:name="com.example.myapplication.RightFragment"-->
<!--        android:layout_width="0dp"-->
<!--        android:layout_height="match_parent"-->
<!--        android:layout_weight="1"-->
<!--        tools:layout="@layout/right_frame" />-->
</LinearLayout>

 

可以看到,现在将右侧碎片替换成了一个FrameLayout中,还记得这个布局吗?在上一章中我们学过,这是Android中最简单的一种布局,所有的控件默认都会摆放在布局的左上角**。由于这里仅需要在布局里放入一个碎片,不需要任何定位,因此非常适合使用FrameLayout**。

 下面我们将在代码中向FrameLayout里添加内容,从而实现动态添加碎片的功能。修改MainActivity中的代码,如下所示

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;public class MainActivity extends AppCompatActivity{boolean signal = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);replaceFragment(new RightFragment());signal = true;ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});}private void replaceFragment(Fragment fragment) {FragmentManager fragmentManager = getSupportFragmentManager();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.right_layout,fragment);transaction.addToBackStack(null);transaction.commit();}public void key_click(View view) {Log.d("MainActivity","button is clicked");if(signal == true){replaceFragment(new AnotherRightFragment());signal = false;}else {replaceFragment(new RightFragment());signal = true;}Toast.makeText(MainActivity.this,"方法2 点击按键",Toast.LENGTH_SHORT).show();}
}

 可以看到,首先我们给左侧碎片中的按钮注册了一个点击事件(直接在left_fragment.xml直接生成onclick),然后调用replaceFragment() 方法动态添加了RightFragment这个碎片。当点击左侧碎片中的按钮时,又会调用replaceFragment() 方法将右侧碎片替换成AnotherRightFragment。结合replaceFragment() 方法中的代码可以看出,动态添加碎片主要分为5步。

  1. 创建待添加的碎片实例。
  2. 获取FragmentManager,在活动中可以直接通过调用getSupportFragmentManager() 方法得到。
  3. 开启一个事务,通过调用beginTransaction() 方法开启。
  4. 向容器内添加或替换碎片,一般使用replace() 方法实现,需要传入容器的id和待添加的碎片实例。
  5. 提交事务,调用commit() 方法来完成。

 这样就完成了在活动中动态添加碎片的功能,重新运行程序,可以看到和之前相同的界面,然后点击一下按钮,按BUTTON一下就会使右边的两个布局切换

4. 在碎片中模拟返回栈 

        在上一小节中,我们成功实现了向活动中动态添加碎片的功能,不过你尝试一下就会发现,通过点击按钮添加了一个碎片之后,这时按下Back键程序就会直接退出。如果这里我们想模仿类似于返回栈的效果,按下Back键可以回到上一个碎片,该如何实现呢?

        其实很简单,FragmentTransaction中提供了一个addToBackStack() 方法,可以用于将一个事务添加到返回栈中,修改MainActivity中的代码,如下所示

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

        这里我们在事务提交之前调用了FragmentTransaction的addToBackStack() 方法,它可以接收一个名字用于描述返回栈的状态,一般传入null 即可。现在重新运行程序,并点击按钮将AnotherRightFragment添加到活动中,然后按下Back键,你会发现程序并没有退出,而是回到了RightFragment界面,继续按下Back键,RightFragment界面也会消失,再次按下Back键,程序才会退出.

5.碎片和活动之间进行通信

虽然碎片都是嵌入在活动中显示的,可是实际上它们的关系并没有那么亲密。你可以看出,碎片和活动都是各自存在于一个独立的类当中的,它们之间并没有那么明显的方式来直接进行通信。如果想要在活动中调用碎片里的方法,或者在碎片中调用活动里的方法,应该如何实现呢?

 为了方便碎片和活动之间进行通信,FragmentManager提供了一个类似于findViewById() 的方法,专门用于从布局文件中获取碎片的实例,代码如下

RightFragment rightFragment = getSupportFragmentManager().findFragmentById(R.id.right_fragment);

调用FragmentManager的findFragmentById() 方法,可以在活动中得到相应碎片的实例,然后就能轻松地调用碎片里的方法了。

 掌握了如何在活动中调用碎片里的方法,那在碎片中又该怎样调用活动里的方法呢?其实这就更简单了,在每个碎片中都可以通过调用getActivity() 方法来得到和当前碎片相关联的活动实例,代码如下

MainActivity activity =  getActivity();

有了活动实例之后,在碎片中调用活动里的方法就变得轻而易举了。另外当碎片中需要使用Context 对象时,也可以使用getActivity() 方法,因为获取到的活动本身就是一个Context 对象。

        这时不知道你心中会不会产生一个疑问:既然碎片和活动之间的通信问题已经解决了,那么碎片和碎片之间可不可以进行通信呢?

        说实在的,这个问题并没有看上去那么复杂,它的基本思路非常简单,首先在一个碎片中可以得到与它相关联的活动,然后再通过这个活动去获取另外一个碎片的实例,这样也就实现了不同碎片之间的通信功能,因此这里我们的答案是肯定的。

6.碎片的生命周期

6.1 碎片的状态和回调

        还记得每个活动在其生命周期内可能会有哪几种状态吗?没错,一共有运行状态、暂停状态、停止状态和销毁状态这4种。类似地,每个碎片在其生命周期内也可能会经历这几种状态,只不过在一些细小的地方会有部分区别。

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

 结合之前的活动状态,相信你理解起来应该毫不费力吧。同样地,Fragment 类中也提供了一系列的回调方法,以覆盖碎片生命周期的每个环节。其中,活动中有的回调方法,碎片中几乎都有,不过碎片还提供了一些附加的回调方法,那我们就重点看一下这几个回调。

  • onAttach():Fragment与Activity关联时调用。
  • onCreate():创建Fragment时调用,用于初始化非视图相关的组件。
  • onCreateView():创建并返回Fragment的视图层次结构。
  • onViewCreated():视图创建完成后调用,用于进一步初始化视图组件(对创建的视图进行进一步初始化,如设置监听器、绑定数据等)。
  • onStart():Fragment对用户可见时调用。
  • onResume():Fragment开始与用户交互时调用。
  • onPause():Fragment即将停止与用户交互时调用。
  • onStop():Fragment对用户不可见时调用。
  • onDestroyView():销毁Fragment的视图层次结构时调用。
  • onDestroy():销毁Fragment时调用。
  • onDetach():Fragment与Activity解除关联时调用。

6.2 体验碎片的生命周期 

为了让你能够更加直观地体验碎片的生命周期,我们还是通过一个例子来实践一下。例子很简单,仍然是在FragmentTest项目的基础上改动的。

修改RightFragment中的代码,如下所示

package com.example.myapplication;import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import androidx.fragment.app.Fragment;public class RightFragment extends Fragment {public static final String TAG = "RightFragment";@Overridepublic void onAttach(Context context) {super.onAttach(context);Log.d(TAG, "onAttach");}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(TAG, "onCreate");}public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {Log.d(TAG, "onCreateView");View view = inflater.inflate(R.layout.right_frame, container, false);return view;}public void onStart() {super.onStart();Log.d(TAG, "onStart");}@Overridepublic void onResume() {super.onResume();Log.d(TAG, "onResume");}@Overridepublic void onPause() {super.onPause();Log.d(TAG, "onPause");}@Overridepublic void onStop() {super.onStop();Log.d(TAG, "onStop");}@Overridepublic void onDestroyView() {super.onDestroyView();Log.d(TAG, "onDestroyView");}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "onDestroy");}@Overridepublic void onDetach() {super.onDetach();Log.d(TAG, "onDetach");}}

我们在RightFragment中的每一个回调方法里都加入了打印日志的代码,然后重新运行程序,这时观察logcat中的打印信息。

可以看到,当RightFragment第一次被加载到屏幕上时,会依次执行onAttach() 、onCreate() 、onCreateView() 、onActivityCreated() 、onStart() 和onResume() 方法。然后点击LeftFragment中的按钮。

        由于AnotherRightFragment替换了RightFragment,此时的RightFragment进入了停止状态,因此onPause() 、onStop() 和onDestroyView() 方法会得到执行。当然如果在替换的时候没有调用addToBackStack() 方法,此时的RightFragment就会进入销毁状态,onDestroy() 和onDetach() 方法就会得到执行。

        接着按下Back键,RightFragment会重新回到屏幕

由于RightFragment重新回到了运行状态,因此onCreateView() 、onActivityCreated() 、onStart() 和onResume() 方法会得到执行。注意此时onCreate() 方法并不会执行,因为我们借助了addToBackStack() 方法使得RightFragment并没有被销毁。

 现在再次按下Back键

依次会执行onPause() 、onStop() 、onDestroyView() 、onDestroy() 和onDetach() 方法,最终将碎片销毁掉。这样碎片完整的生命周期你也体验了一遍,是不是理解得更加深刻了?

 另外值得一提的是,在碎片中你也是可以通过onSaveInstanceState() 方法来保存数据的,因为进入停止状态的碎片有可能在系统内存不足的时候被回收。保存下来的数据在onCreate() 、onCreateView() 和onActivityCreated() 这3个方法中你都可以重新得到,它们都含有一个Bundle类型的savedInstanceState 参数。具体的代码我就不在这里给出了,如果你忘记了该如何编写。

参考:安卓-碎片的使用入门_android 碎片知识点讲解-CSDN博客

 

 

 

相关文章:

安卓-碎片的使用入门

1.碎片(Fragment)是什么 Fragment是依赖于Activity的&#xff0c;不能独立存在的,是Activity界面中的一部分&#xff0c;可理解为模块化的Activity,它能让程序更加合理和充分地利用大屏幕的空间&#xff0c;因而在平板上应用得非常广泛. Fragment不能独立存在&#xff0c;必须…...

华为IPD流程学习之——深入解读123页华为IPD流程体系设计方法论PPT

该方案全面介绍了华为IPD流程体系设计方法论&#xff0c;包括流程体系建设的背景、理念、架构、核心特征、构建模型、与组织和战略的关系、运营机制、数字化转型以及流程管理组织等内容&#xff0c;旨在为企业提供一套系统的流程体系建设指导&#xff0c;以提升运营效率、质量和…...

DriveMLLM:一个专为自动驾驶空间理解任务设计的大规模基准数据集

2024-11-20&#xff0c; 由武汉大学、中国科学院自动化研究所、悉尼科技大学、牛津大学等合创建了DriveMLLM数据集&#xff0c;该数据集是自动驾驶领域首个专为评估多模态大型语言模型&#xff08;MLLMs&#xff09;空间理解能力而设计的基准&#xff0c;对于推动自动驾驶技术的…...

高效处理 iOS 应用中的大规模礼物数据:以直播项目为例(1-礼物池)

引言 在现代iOS应用开发中&#xff0c;处理大规模数据是一个常见的挑战。尤其实在直播项目中&#xff0c;礼物面板作为展示用户互动的重要部分&#xff0c;通常需要实时显示海量的礼物数据。这些数据不仅涉及到不同的区域、主播的动态差异&#xff0c;还需要保证高效的加载与渲…...

python的函数与递归

需求&#xff1a; 编写一个函数&#xff0c;计算斐波那契数列的第 N 项&#xff0c;并使用递归实现。 为了计算斐波那契数列的第 N 项&#xff0c;可以使用递归方法。斐波那契数列的定义是&#xff1a; F(0) 0 F(1) 1 对于 n > 2&#xff0c;F(n) F(n-1) F(n-2)&#xf…...

RabbitMQ学习-Seven

再SpringBoot中使用MQ 1.创建SpringBoot项目 除了我们平常使用的一些工具依赖&#xff0c;还需要选择这个Spring for RabbitMQ依赖 2.需要在application.yml文件中进行配置 server:port :9090 spring:application:name:producerrabbitmq:host: 你的主机名port: 5672virtual-…...

中科亿海微SoM模组——波控处理软硬一体解决方案

本文介绍的波控处理软硬一体解决方案主要是面向相控阵天线控制领域&#xff0c;波控处理通过控制不同天线组件的幅相来调整天线波束的方向和增益&#xff0c;实现高精度角度控制和高增益。本方案由波控处理板、波控处理控制软件算法和上位机软件共同构成。波控处理SoM模组原型样…...

开源法律、政策和实践

#一切皆可开源# 木兰社区对《Open Source Law,Policy and Practice 》这本书的第二版进行了翻译&#xff0c;并发布在了gitee上。这本书是对开源文化、开源政策、法律的全面介绍。目录如下&#xff1a; 1 Open Source as Philosophy,Methodology,and CommerceUsing Law with …...

【计算视觉算法与应用】金字塔,下采样Gaussian Pyramid. 上采用 Laplacian Pyramid (code: py)

金字塔&#xff08;Pyramid&#xff09;在图像处理中主要用于多尺度分析和图像压缩。常见的图像金字塔有两种&#xff1a; 高斯金字塔&#xff08;Gaussian Pyramid&#xff09;&#xff1a;用于下采样图像&#xff0c;生成分辨率逐渐降低的图像序列。拉普拉斯金字塔&#xff…...

基于BERT的语义分析实现

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…...

DNS查询工具

DNS查询工具是用于查询和获取域名相关信息的工具。通过这些工具&#xff0c;您可以获取到诸如IP地址、邮件服务器以及域名服务器等信息&#xff0c;这对于排查问题、设置域名配置以及确保网站正常运行都非常重要。 以下是五款常用的DNS记录查询工具&#xff1a; MxToolbox MxTo…...

ODB 框架

目录 概述 基本工作原理 映射C对象到数据库表 从数据库中加载对象 持久化C对象到数据库 ODB常用接口 表创建预处理 #pragma db Object table 数据表属性 id auto column&#xff08;“xxx”&#xff09; type("xxx") unique index null default&…...

Ubuntu WiFi检测

ubuntu检测到多个同名wifi&#xff0c;怎么鉴别假冒的wifi&#xff1f; 在Ubuntu中&#xff0c;如果检测到多个同名的Wi-Fi网络&#xff0c;可能存在假冒的Wi-Fi&#xff08;例如“蜜罐”攻击&#xff09;。以下是一些鉴别假冒Wi-Fi的方法&#xff1a; 检查信号强度&#xff1a…...

QILSTE H4-108TCG高亮纯lu光LED灯珠 发光二极管LED

型号&#xff1a;H4-108TCG 在电子领域&#xff0c;H4-108TCG LED以其卓越的性能和微小的尺寸1.6x0.8x0.4mm脱颖而出。这款高亮纯绿光LED&#xff0c;采用透明平面胶体&#xff0c;符合EIA标准包装&#xff0c;是环保产品&#xff0c;符合ROHS标准。防潮等级为Level 3&#xf…...

IP与“谷子”齐飞,阅文“乘势而上”?

爆火的“谷子经济”&#xff0c;又捧出一只“潜力股”。 近日&#xff0c;阅文集团股价持续上涨&#xff0c;5日累计涨幅达13.20%。这其中&#xff0c;周三股价一度大涨约15%至29.15港元&#xff0c;强势突破20日、30日、120日等多根均线&#xff0c;市值突破280亿港元关口。 …...

Java阶段三05

第3章-第5节 一、知识点 动态代理、jdk动态代理、cglib动态代理、AOP、SpringAOP 二、目标 理解什么是动态代理和它的作用 学会使用JAVA进行动态代理 理解什么是AOP 学会使用AOP 理解什么是AOP的切入点 三、内容分析 重点 理解什么是动态代理和它的作用 理解什么是AO…...

C# yield 关键字

文章目录 前言一、yield 关键字的语法形式及使用场景&#xff08;一&#xff09;yield return&#xff08;二&#xff09;yield break 二、yield 关键字的工作原理三、yield 关键字的优势与应用场景&#xff08;一&#xff09;优势&#xff08;二&#xff09;应用场景 前言 在 …...

SpringBoot开发——结合Nginx实现负载均衡

文章目录 负载均衡介绍介绍Nginx实现负载均衡的示例图:负载均衡策略1.Round Robin:2.Least Connections:3.IP Hash :4.Generic Hash:5.Least Time (NGINX Plus only)6.Random:Nginx+SpringBoot实现负载均衡环境准备Nginx 配置负载均衡测试负载均衡介绍 介绍 在介绍Nginx的负…...

RabbitMQ在手动消费的模式下设置失败重新投递策略

最近在写RabbitMQ的消费者&#xff0c;因为业务需求&#xff0c;希望失败后重试一定次数&#xff0c;超过之后就不处理了&#xff0c;或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的&#xff0c;问了kimi&#xff0c;按它的方法配置之后&#xff0c;发…...

TsingtaoAI具身智能高校实训方案通过华为昇腾技术认证

日前&#xff0c;TsingtaoAI推出的“具身智能高校实训解决方案-从AI大模型机器人到通用具身智能”基于华为技术有限公司AI框架昇思MindSpore&#xff0c;完成并通过昇腾相互兼容性技术认证。 TsingtaoAI&华为昇腾联合解决方案 本项目“具身智能高校实训解决方案”以实现高…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...