安卓-碎片的使用入门
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步。
- 创建待添加的碎片实例。
- 获取FragmentManager,在活动中可以直接通过调用getSupportFragmentManager() 方法得到。
- 开启一个事务,通过调用beginTransaction() 方法开启。
- 向容器内添加或替换碎片,一般使用replace() 方法实现,需要传入容器的id和待添加的碎片实例。
- 提交事务,调用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的,不能独立存在的,是Activity界面中的一部分,可理解为模块化的Activity,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用得非常广泛. Fragment不能独立存在,必须…...
华为IPD流程学习之——深入解读123页华为IPD流程体系设计方法论PPT
该方案全面介绍了华为IPD流程体系设计方法论,包括流程体系建设的背景、理念、架构、核心特征、构建模型、与组织和战略的关系、运营机制、数字化转型以及流程管理组织等内容,旨在为企业提供一套系统的流程体系建设指导,以提升运营效率、质量和…...
DriveMLLM:一个专为自动驾驶空间理解任务设计的大规模基准数据集
2024-11-20, 由武汉大学、中国科学院自动化研究所、悉尼科技大学、牛津大学等合创建了DriveMLLM数据集,该数据集是自动驾驶领域首个专为评估多模态大型语言模型(MLLMs)空间理解能力而设计的基准,对于推动自动驾驶技术的…...
高效处理 iOS 应用中的大规模礼物数据:以直播项目为例(1-礼物池)
引言 在现代iOS应用开发中,处理大规模数据是一个常见的挑战。尤其实在直播项目中,礼物面板作为展示用户互动的重要部分,通常需要实时显示海量的礼物数据。这些数据不仅涉及到不同的区域、主播的动态差异,还需要保证高效的加载与渲…...
python的函数与递归
需求: 编写一个函数,计算斐波那契数列的第 N 项,并使用递归实现。 为了计算斐波那契数列的第 N 项,可以使用递归方法。斐波那契数列的定义是: F(0) 0 F(1) 1 对于 n > 2,F(n) F(n-1) F(n-2)…...
RabbitMQ学习-Seven
再SpringBoot中使用MQ 1.创建SpringBoot项目 除了我们平常使用的一些工具依赖,还需要选择这个Spring for RabbitMQ依赖 2.需要在application.yml文件中进行配置 server:port :9090 spring:application:name:producerrabbitmq:host: 你的主机名port: 5672virtual-…...
中科亿海微SoM模组——波控处理软硬一体解决方案
本文介绍的波控处理软硬一体解决方案主要是面向相控阵天线控制领域,波控处理通过控制不同天线组件的幅相来调整天线波束的方向和增益,实现高精度角度控制和高增益。本方案由波控处理板、波控处理控制软件算法和上位机软件共同构成。波控处理SoM模组原型样…...
开源法律、政策和实践
#一切皆可开源# 木兰社区对《Open Source Law,Policy and Practice 》这本书的第二版进行了翻译,并发布在了gitee上。这本书是对开源文化、开源政策、法律的全面介绍。目录如下: 1 Open Source as Philosophy,Methodology,and CommerceUsing Law with …...
【计算视觉算法与应用】金字塔,下采样Gaussian Pyramid. 上采用 Laplacian Pyramid (code: py)
金字塔(Pyramid)在图像处理中主要用于多尺度分析和图像压缩。常见的图像金字塔有两种: 高斯金字塔(Gaussian Pyramid):用于下采样图像,生成分辨率逐渐降低的图像序列。拉普拉斯金字塔ÿ…...
基于BERT的语义分析实现
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...
DNS查询工具
DNS查询工具是用于查询和获取域名相关信息的工具。通过这些工具,您可以获取到诸如IP地址、邮件服务器以及域名服务器等信息,这对于排查问题、设置域名配置以及确保网站正常运行都非常重要。 以下是五款常用的DNS记录查询工具: MxToolbox MxTo…...
ODB 框架
目录 概述 基本工作原理 映射C对象到数据库表 从数据库中加载对象 持久化C对象到数据库 ODB常用接口 表创建预处理 #pragma db Object table 数据表属性 id auto column(“xxx”) type("xxx") unique index null default&…...
Ubuntu WiFi检测
ubuntu检测到多个同名wifi,怎么鉴别假冒的wifi? 在Ubuntu中,如果检测到多个同名的Wi-Fi网络,可能存在假冒的Wi-Fi(例如“蜜罐”攻击)。以下是一些鉴别假冒Wi-Fi的方法: 检查信号强度:…...
QILSTE H4-108TCG高亮纯lu光LED灯珠 发光二极管LED
型号:H4-108TCG 在电子领域,H4-108TCG LED以其卓越的性能和微小的尺寸1.6x0.8x0.4mm脱颖而出。这款高亮纯绿光LED,采用透明平面胶体,符合EIA标准包装,是环保产品,符合ROHS标准。防潮等级为Level 3…...
IP与“谷子”齐飞,阅文“乘势而上”?
爆火的“谷子经济”,又捧出一只“潜力股”。 近日,阅文集团股价持续上涨,5日累计涨幅达13.20%。这其中,周三股价一度大涨约15%至29.15港元,强势突破20日、30日、120日等多根均线,市值突破280亿港元关口。 …...
Java阶段三05
第3章-第5节 一、知识点 动态代理、jdk动态代理、cglib动态代理、AOP、SpringAOP 二、目标 理解什么是动态代理和它的作用 学会使用JAVA进行动态代理 理解什么是AOP 学会使用AOP 理解什么是AOP的切入点 三、内容分析 重点 理解什么是动态代理和它的作用 理解什么是AO…...
C# yield 关键字
文章目录 前言一、yield 关键字的语法形式及使用场景(一)yield return(二)yield break 二、yield 关键字的工作原理三、yield 关键字的优势与应用场景(一)优势(二)应用场景 前言 在 …...
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的消费者,因为业务需求,希望失败后重试一定次数,超过之后就不处理了,或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的,问了kimi,按它的方法配置之后,发…...
TsingtaoAI具身智能高校实训方案通过华为昇腾技术认证
日前,TsingtaoAI推出的“具身智能高校实训解决方案-从AI大模型机器人到通用具身智能”基于华为技术有限公司AI框架昇思MindSpore,完成并通过昇腾相互兼容性技术认证。 TsingtaoAI&华为昇腾联合解决方案 本项目“具身智能高校实训解决方案”以实现高…...
【Linux】线程池设计 + 策略模式
🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 线程池 1-1 ⽇志与策略模式1-2 线程池设计1-3 线程安全的单例模式1-3-1 什么是单例模式1-3-2 单例模式的特点1-3-3 饿汉实现⽅式和懒汉实现⽅式1-3-4 饿汉…...
网络原理(一):应用层自定义协议的信息组织格式 HTTP 前置知识
目录 1. 应用层 2. 自定义协议 2.1 根据需求 > 明确传输信息 2.2 约定好信息组织的格式 2.2.1 行文本 2.2.2 xml 2.2.3 json 2.2.4 protobuf 3. HTTP 协议 3.1 特点 4. 抓包工具 1. 应用层 在前面的博客中, 我们了解了 TCP/IP 五层协议模型: 应用层传输层网络层…...
Python-链表数据结构学习(1)
一、什么是链表数据? 链表是一种通过指针串联在一起的数据结构,每个节点由2部分组成,一个是数据域,一个是指针域(存放下一个节点的指针)。最后一个节点的指针域指向null(空指针的意思࿰…...
性能优化经验:关闭 SWAP 分区
关闭 SWAP 分区,特别是在性能敏感场景(如 Elasticsearch 服务)中,主要与 SWAP 的工作机制和对应用性能的影响有关。以下是详细原因: 1. SWAP 的工作机制导致高延迟 SWAP 是什么: SWAP 分区是系统将物理内存…...
SpringBoot小知识(2):日志
日志是开发项目中非常重要的一个环节,它是程序员在检查程序运行的手段之一。 1.日志的基础操作 1.1 日志的作用 编程期调试代码运营期记录信息: * 记录日常运营重要信息(峰值流量、平均响应时长……) * 记录应用报错信息(错误堆栈) * 记录运维过程数据(…...
java虚拟机——jvm是怎么去找垃圾对象的
JVM(Java虚拟机)通过特定的算法和机制来查找和识别垃圾对象,以便进行垃圾回收。以下是JVM查找垃圾对象的主要方法和步骤: 一、可达性分析法 JVM使用可达性分析法来识别垃圾对象。这种方法从一组称为“GC Roots”的对象作为起始点…...
Macos远程连接Linux桌面教程;Ubuntu配置远程桌面;Mac端远程登陆Linux桌面;可能出现的问题
文章目录 1. Ubuntu配置远程桌面2. Mac端远程登陆Linux桌面3. 可能出现的问题1.您用来登录计算机的密码与登录密钥环里的密码不再匹配2. 找不到org->gnome->desktop->remote-access 1. Ubuntu配置远程桌面 打开设置->共享->屏幕共享。勾选允许连接控制屏幕&…...
hadoop_HA高可用
秒懂HA HA概述HDFS-HA工作机制工作要点元数据同步参数配置手动故障转移自动故障转移工作机制相关命令 YARN-HA参数配置自动故障转移机制相关命令 附录Zookeeper详解 HA概述 H(high)A(avilable): 高可用,意味着必须有容错机制,不能因为集群故障…...
【MySQL】MySQL中的函数之JSON_ARRAY_APPEND
在 MySQL 8.0 及更高版本中,JSON_ARRAY_APPEND() 函数用于在 JSON 数组的指定位置追加一个或多个值。这个函数非常有用,特别是在你需要在 JSON 数组的末尾或特定位置添加新的元素时。 基本语法 JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ..…...
torch.is_nonzero(input)
torch.is_nonzero(input) input: 输入张量 若输入是 不等于零的单元素张量 则返回True,否则返回False 不等于零的单元素张量:torch.tensor([0.]) 或 torch.tensor([0]) 或 torch.tensor([False])单元素张量: 只有一个数 的张量 import torch print(t…...
武汉网站建设公司/市场调研报告模板范文
android contentView()本身就是framlayout 在activity中 oncreate方法中布局最外层是framlayout这时我们可以使用merge标签 当使用<include>标签时当父布局最外层,与include布局最外层是相同布局时在include布局最外层就可以使用<merge>标签 示例图 父…...
网站title怎么修改/网站域名在哪买
Override public String useChineseSocket() { String msg“使用中国双叉充电”; return msg; } } 复制代码 适配器(Adapter)类: /** 定义适配器类 中国双叉转为欧洲三叉 */ public class ChineseAdapterEurope extends EuropeSoc…...
网站搭建怎么收费/百度推广客户端官方下载
google v8 Date 以double 类型储存从1970开始的毫秒数。 FILETIME 储存从1601年开始的 (100纳秒)数 1 void v8date_to_systemtime(v8::Handle<Value> dateVal,LPSYSTEMTIME st)2 {3 Local<Date> d Date::Cast(*dateVal);4 __int64 …...
好的网站设计作品/比较好的免费网站
spring异步调用注解Async实现原理分析 1、首先看下注解,可以加在类上,也可以加在方法上 2、需要在启动类加上EnableAsync注解 导入了AsyncConfigurationSelector 调用selectImports方法。默认会注入ProxyAsyncConfiguraion 看下ProxyAsyncConfigurat…...
南京计算机培训机构哪个最好/汕头seo公司
在此详细记录 Android 开发工具的安装过程,以备后查。在 Windows 7 下使用虚拟机进行,也可以直接用 Ubuntu 安装光碟做一个真实环境虚拟机:VirtualBox 3.2.12(下载地址:http://download.virtualbox.org/virtualbox/3.2.12/Virtual…...
石桥铺做网站/网上软文发稿平台
中国医药流通行业深度分析及十四五发展规划咨询建议报告2022-2028年版 【报告目录】: 第1章:中国医药流通行业发展背景与现状1.1 医药流通行业发展概况及特点 1.1.1 医药流通行业发展概况 1.1.2 医药流通行业发展特点 1.1.3 医药流通行业产业链 1.2 医药流通行…...