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

FyListen——生命周期监听器(设计原理之理解生命周期)

FyListen——生命周期监听器(设计原理之理解生命周期)

FyListen 的核心原理有两个:

  1. 通过子Fragment对Activity、Fragment进行生命周期监听
  2. Java8 接口特性 default

1. 什么是上下文Context

请添加图片描述

这是一个装饰器模式, ContextImpl 是 Context 的基础实现类, ContextWrapper 是对 ContextImpl 的包装类。ContextThemeWrapper 是对装饰器的再装饰,又增加了一些功能。

1.1 如何获取 Context?

获取 Context 的方法有很多:getContext(), getBaseContext(), getApplication(), getApplicationContext()。我们来看一下他们的区别:

getApplication()和 getApplicationContext() 获取到的就是同一个对象,只是使用的范围不一样:

  • getApplication() 只有 Activity 和 Service 才有。
  • 想要在其他地方获取 Application 只能通过 getApplicationContext().

getContext(), getBaseContext()和 getApplicationContext() 有什么区别?

  • Activity,Service 和 Application 都有 getBaseContext(),getApplicationContext() 这两个方法,但没有 getContext() 方法。

  • getContext() 方法只有在 Fragment 中才有,获取的是寄主对象,也就是 Activity。

    所以 Fragment 必须依赖于 Activity 存在

1.2 Application 有什么用?

Application 是全局单例,可以通过 getApplication() 和 getApplicationContext() 获取。

需要注意的是,如果在 application 中调用 context 的方法,必须在 attachBaseContext() 之后,在此之前 context 是没有赋值的。

2. Activity 与 Fragment 生命周期绑定原理

先来看一张Fragment状态转移图:(图来自稀土掘金)

img

这张图的解读可以看到下面这张表,Activity 管理 Fragment 生命周期的方式是在 Activity 的生命周期方法中调用 FragmentManager 的对应方法,通过 FragmentManager 将现有的 Fragment 迁移到下一个状态,同时触发相应的生命周期函数:

Activity生命周期函数FragmentManager触发的方法Fragmet你状态转移Fragment生命周期回调
onCreate()dispatchCreateINITIALIZING->CREATEDonAttach()、onCreate()
dispatchActivityCreated()CREATED->ACTIVITY_CREATEDonCreateView()、onActivityCreated()、
onStart()dispatchStartACTIVITY_CREATED->STARTEDonStart()
onResume()dispatchResumeSTARTED->RESUMEDonResume()
onPausedispatchPauseRESUMED->STARTEDonPause()
onStopdispatchStopSTARTED->STOPPEDonStop()
onDestroydispatchDestroySTOPPED->ACTIVITY_CREATED->CREATED->CREATED->INITIALIZINGonDestroyView()、onDestroy()、onDetach()

我们从源码角度来看一下是如何绑定的生命周期,首先我们需要知道,Activity 生命周期是由 AMS(ActivityManagerService)管理、回调的,这部分请大家在 AMS 专题学习。便于理解,我们提前看到源码中关于Fragment的状态转移代码处理:

需要提醒的Java基础是,switch: 一旦switch表达式与某个case分支匹配,则从该分支的语句开始执行,一致执行下去!其后所有case分支的语句也会被执行,直到遇到break语句!!!

//[FragmentManager.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) {//newState是Fragment将要被转移到的状态state//f.mState是Fragment现有的状态stateif(f.mState <= newState){switch(f.mState){case Fragment.INITIALIZING://Fragment当前状态还在INITIALIZINGActivity调用了onCreate(),newState是CREATEDFragment进行状态转移if(newState > Fragment.INITIALIZING){f.onAttach();dispatchOnFragmentAttached();if(!f.mIsCreated){//如果fragment还没create()f.performCreate();dispatchOnFragmentCreated();}else{//如果fragment过去已经create()过了,只不过是detach()了,并没有销毁。也就是这个Fragment虽然生命结束了,但后来又被加载使用了(复用了)f.mState = Fragment.CREATED;}}case Fragment.CREATED:if(newState > Fragment.CREATED){//Fragment当前状态在CREATED,但Activity紧接着又将状态调整为ACTIVITY_CREATED,Fragment进行状态转移f.mView = f.performCreateView();if(f.mView!=null){//如果没有view,就不往它的子Fragment进行生命周期回调分发了dispatchOnFragmentViewCreated();}f.performActivityCreated();dispatchOnFragmentActivityCreated();}case Fragment.ACTIVITY_CREATED:if(newState > Fragment.ACTIVITY_CREATED){//只进行状态转移f.mState = Fragment.STOPPED;}case Fragment.STOPPED:if(newState > Fragment.STOPPED){f.performStart();dispatchOnFragmentStarted();}case Fragment.STARTED:if(newState > Fragment.STARTED){f.performResume();dispatchOnFragmentResumed();}}}else if(f.mState > newState){//反向转移switch(f.mState){case Fragment.RESUMED:if(newState < Fragment.RESUMED){f.performPause();dispatchOnFragmentPaused();}case Fragment.STARTED:if(newState < Fragment.STARTED){f.performStop();dispatchOnFragmentStopped();}case Fragment.STOPPED:case Fragment.ACTIVITY_CREATED:if(newState < Fragment.ACTIVITY_CREATED){f.performDestroyView();dispatchOnFragmentViewDestroyed();}case Fragment.CREATED:if(newState < Fragment.CREATED){f.performDestroy();dispatchOnFragmentDestroy();}f.performDetach();dispatchOnFragmentDetached();}if(f.mState != newState){f.mState = newState;}}
}

我们了解了 Fragment 的生命周期是由于 Activity 生命周期的回调,设定了 Fragment 应当到的 newState,然后让 Fragment 进行状态转移,转移的过程中回调 Fragment 的生命周期。所以我们主要需要看 Activity 是如何设置 newState 的。从 AMS 回调 Activity 的 performXXX() 看起:

2.1 AMS->Activity.performCreate()

  1. 在 Activity 的 onCreate() 中将 Fragment 的状态转移目标 newState 设置为了 CREATED,状态转移期间回调了Fragment的 onAttach() 和 onCreate()
  2. performCreate()又将 Fragment 的状态转移目标newState设置为了 ACTIVITY_CREATED,Fragment在状态转移期间回调了Fragment的 onCreateView() 和 onActivityCreate()
//[Activity.java]
final void performCreate(Bundle icicle, PersistableBundle persistentState) {//调用Activity的onCreate()方法,其中回调了Fragment的onAttach()和onCreate()方法if (persistentState != null) {onCreate(icicle, persistentState);} else {onCreate(icicle);}//调用到moveToState,且newState为Fragment.ACTIVITY_CREATED,状态转移过程中,回调了Fragment的onCreateView()和onActivityCreate().mFragments.dispatchActivityCreated();
}protected void onCreate(@Nullable Bundle savedInstanceState) {//调用到moveToState,且newState为Fragment.CREATED,在状态转移期间回调了Fragment的onAttach()和onCreate()方法mFragments.dispatchCreate();//Application的Lifecycle回调dispatchActivityCreated(savedInstanceState);
}

2.2 AMS->performStart()

  1. 调用了 Activity 的 onStart()
  2. 将Fragment的状态转移目标newState设置为了STARTED,Fragment在期间回调了Fragment的 onStart() 方法
//[Activity.java]
final void performStart(String reason){//回调了 activity.onStart(),其中进行Application的Lifecycle回调mInstrumentation.callActivityOnStart(this);//调用到moveToState,且newState为Fragment.STARTED,其中回调了onStart()方法。虽然在switch中将Fragment的状态停留在了STOPPED,但在moveToState()方法的最后,又将Fragment的状态设置到了STARTED。mFragments.dispatchStart()
}

2.3 AMS->performResume()

  1. 调用了 Activity 的 onResume()
  2. 将Fragment的状态转移目标newState设置为了RESUMED,Fragment在状态转移期间回调了Fragment的 onResume();
//[Activity.java]
final void performResume(boolean followedByPause, String reason){//如果activity之前不是started的,会进入此方法,确保将activity变为startperformRestart(true,reason);//如果activity之前是start的://回调activity.onResume(),里面回调了 Application的LifecyclemInstrumentation.callActivityOnResume(this);//调用到moveToState,且newState为Fragment.RESUMED,状态转移期间回调了Fragment的onResume()方法mFragments.dispatchResume();
}

2.4 AMS->performPause()

【注意!!!】我们发现,从这里开始,是先从Fragment开始状态转换,而且是往回转移,newState<f.mState,然后才调用Activity的生命周期回调

  1. 注意,状态转移设为newState=STARTED,开始往回转移!!!
  2. Fragment状态转移期间回调了onPause()方法
  3. 然后才调用Activity的onPause()方法
//[Activity.java]
final void performPause(boolean preserveWindow, String reason) {//在此之前状态为RESUMED,由于f.mState<newState,将进行往回状态转移!//Fragment状态转移到STARTED期间回调了Fragment的onPause()mFragments.dispatchPause();//调用Activity的onPause(),同时回调Application的LifecycleonPause();
}

2.5 AMS->performStop()

【注意!!!】先从Fragment开始状态转换,而且是往回转移,newState<f.mState,然后才调用Activity的生命周期回调

  1. 注意,状态转移目标设为newState = STOPPED,往回状态转移
  2. Fragment状态转移期间回调了 onStop()方法
  3. 然后才调用Activity的onStop()方法
//[Activity.java]
final void performStop(boolean preserveWindow, String reason) {//Fragment状态转移到STOPPED,往回状态转移期间,回调了Fragment的onStop()方法mFragments.dispatchStop();//其中回调了Activity的onStop(),同时回调Application中的监听LifecyclemInstrumentation.callActivityOnStop(this);
}

2.6 AMS->performRestart()

Activity可能会在onStop()之后又onRestart(),需要注意的是,这里并没有回调Fragment的生命周期,只调用了activity的onRestart(),并调用performStart(),后续的生命周期回调就和onStart()之后的一致了

//[Activity.java]
final void performRestart(boolean start, String reason) {//先判断之前是否为Stop状态if(mStopped){mStopped = false;//调用Activity的onRestart()回调mInstrumentation.callActivityOnRestart(this);//里面调用了Activity的onStart(),并进行Fragment状态转移与生命周期回调performStart();}
}final void performStart(String reason) {//调用Activity.onStart(),并回调Application的Lifecycle,通知Application这个activity的生命周期现状mInstrumentation.callActivityOnStart(this);//newState=STARTED,Fragment状态从STOPPED到STARTED状态转移,期间回调了Fragment的onStart()mFragments.dispatchStart();
}

2.7 AMS->performDestroy()

【注意!!!】先从Fragment开始状态转换,而且是往回转移,newState<f.mState,然后才调用Activity的生命周期回调

  1. 先进行Fragment状态转移,newState=INITIALIZING,期间回调了Fragment的onDestroyView,onDestroy,onDetach
  2. Fragment状态转移完成,才进行Activity的onDestroy()
//[Activity.java]
final void performDestroy(){//先进行Fragment状态转移,newState=INITIALIZING,期间回调了Fragment的onDestroyView,onDestroy,onDetachmFragments.dispatchDestroy();//Fragment状态转移完成,才进行Activity的onDestroy()onDestroy();
}

我们回到 moveToState 来看一下是怎么连着回调三个Fragment生命周期的,需要注意,此时f.mState = STOPPED,newState=INITIALIZING:

需要提醒的Java基础是,switch: 一旦switch表达式与某个case分支匹配,则从该分支的语句开始执行,一致执行下去!其后所有case分支的语句也会被执行,直到遇到break语句!!!

//[FragmentManager.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) {if(f.mState 《= newState){//...}else if(f.mState > newState){switch(f.mState){//...case Fragment.STOPPED://分支判断成功,继续执行后续case分支语句,直到遇到breakcase Fragment.ACTIVITY_CREATE:if(newState < Fragment.ACTIVITY_CREATED){//1. 回调Fragment的onDestroyView()f.performDestroyView();//把该事件也分发给f的子FragmentdispatchOnFragmentViewDestroyed();}case Fragment.CREATED:if(newState < Fragment.ACTIVITY_CREATED){//2. 回调Fragment的onDestroy()f.performDestroy();//把该事件也分发给f的子FragmentdispatchOnFragmentDestroyed();//3. 回调Fragment的onDetach()f.performDetach();//把该事件也分发给f的子FragmentdispatchOnFragmentDetached();  }//switch end}}//状态转移完成,最终更新f.mState = INITIALIZINGif(f.mState != newState){f.mState = newState;}
}

至此,我们分析完了生命周期回调。如果你比较细心,会发现这里除了处理fragment的生命周期,还有的时候会处理fragment的动画和view的显示。

2. 补充:Fragment生命周期除了自动由 Activity 来回调,也可以由用户操控 FragmentTansaction 进行 Fragment 的调度时候回调生命周期:

先来看这张图:(图源稀土掘金)

img

我们经常使用 FragmentTransaction 中的 add()、remove()、replace()、attach()、detach()、hide()、show() 等方法对 Fragment进行操作,这些方法都会使 Fragment 的状态发生变化,出发对应的生命周期函数。默认 Activity 处于 Resume 状态:

  • add/remove 操作会引起 Fragment 在 INITIALIZING 和 RESUMED 这两个状态之间迁移
  • attach/detach操作会引起 Fragment 在 CREATED 和 RESUMED 两个状态之间迁移

add() 需要注意的是,如果Activity处于 STARTED 状态,Fragment 是无法进入 RESUMED 状态的,只有当 Activity 进入 RESUME 状态才会通知 Fragment 进入 RESUMED。

hide/show方法内部其实调用了 FragmentTransaction 的add/remove 方法。

3. Fragment 与 子Fragment 生命周期绑定原理

我们观察到 Fragment 中也持有一个 FragmentManager:mChildFragmentManage 用于管理子Fragment。所以在生命周期事件分发过程中,会呈树形结构向所有子Fragment进行分发:

//[Fragment.java]
public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {//上层管理当前Fragment的FragmentManagerFragmentManagerImpl mFragmentManager;//当前Fragment用于管理子Fragment的fm,在生命周期回调中,会同时分发给 MChildFragmentManager 中的所有子FragmentFragmentManagerImpl mChildFragmentManager;//所属的父FragmentFragment mParentFragment;
}

FragmentManager 中管理着 Fragments:mAdds 和 mActive:

//[FragmentManager.java]
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {//当前活跃的FragmentSparseArray<Fragment> mActive;//所有已添加的Fragmentfinal ArrayList<Fragment> mAdded = new ArrayList<>();//管理的其他信息ArrayList<BackStackRecord> mBackStack;ArrayList<Fragment> mCreatedMenus;//...//分发生命周期:以dispatchResume()为例public void dispatchResume(){mStateSaved = false;//进行Fragment的状态转移dispatchMoveToState(Fragment.RESUMED);}//其中通过moveToState先进行预处理,即找到所有当前FragmentManager所管理的Fragment进行逐个事件分发private void dispatchMoveToState(int state) {if (mAllowOldReentrantBehavior) {moveToState(state, false);} else {try {mExecutingActions = true;moveToState(state, false);} finally {mExecutingActions = false;}}execPendingActions();}//拿到 mAdds 和 mActive 中的Fragment去分发事件(逐个让他们去进行状态转移)//注意这个是两个参数的 moveToState(),真正状态转移的moveToState()方法是四个参数的,注意区分void moveToState(int newState,boolean always){if (mActive != null) {final int numAdded = mAdded.size();for (int i = 0; i < numAdded; i++) {Fragment f = mAdded.get(i);//逐个fragment进行状态转移moveFragmentToExpectedState(f);}final int numActive = mActive.size();for (int i = 0; i < numActive; i++) {Fragment f = mActive.valueAt(i);if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {//逐个fragment进行状态转移moveFragmentToExpectedState(f);}}}}//moveFragmentToExceptedState()通过四个参数的moveToState()让fragment进行状态转移void moveFragmentToExceptedState(final Fragment f){int nextState = mCurState;//新状态被标记在成员变量,不作为参数传入,简化代码//进行状态转移,具体的我们之前已经看过了moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);}}

4. Activity与Fragment的树形结构

既然我们已经知道了 Fragment 的生命周期可以由 Activity 或者 Fragment 进行回调,那么我们就可以通过这个特性进行 Activity 或者 父Fragment生命周期的监听!!!主流框架 Glide 中生命周期监听的方式,也是利用了这个特性。我画了两张图,大家先感性地认知一下 Fragment 监听 Activity 生命周期的构造:

Activity与Fragment的树形结构:

请添加图片描述

我们可以看到,这是一个可以找到父节点的多叉树。

fragment想要与Activity通信可以通过Fragment中的 FragmentHostCallback类型对象mHost:里面存了Fragment所依存的Activity实例、主线程Handler。Fragment中启动Activity,也是通过这个对象,让上层去执行启动Activity的请求。

5. 使用 Java8 接口特性 default 进行外观设计

java8 之前,往接口里新加一个方法,那么所有的实现类都需要变动,都需要同步实现这个方法。
java8 给接口新增了两个关键字:default static
使得可以往接口里添加默认方法,子类可以无需变动。

同时,这也使得接口中的方法并不需要全都实现,只需要重写需要的方法即可!

相关文章:

FyListen——生命周期监听器(设计原理之理解生命周期)

FyListen——生命周期监听器&#xff08;设计原理之理解生命周期&#xff09; FyListen 的核心原理有两个&#xff1a; 通过子Fragment对Activity、Fragment进行生命周期监听Java8 接口特性 default 1. 什么是上下文Context 这是一个装饰器模式&#xff0c; ContextImpl 是 …...

Element UI框架学习篇(六)

Element UI框架学习篇(六) 1 删除数据 1.1 前台核心函数 1.1.1 elementUI中的消息提示框语法 //①其中type类型和el-button中的type类型是一致的,有info灰色,success绿色,danger红色,warning黄色,primary蓝色 //②message是你所要填写的提示信息 //③建议都用,因为比双引号…...

Python如何安装模块,python模块安装失败的原因以及解决办法

前言 今天来给刚开始学习python的朋友讲解一下 如何安装python模块, python模块安装失败的原因以及解决办法 很多朋友拿到代码之后&#xff0c;就开始复制粘贴 --> 然后右键进行运行 结果就是报错说 没有这个模块 得安装啥的 Python模块安装 一. 打开命令提示符 win …...

《NFL橄榄球》:洛杉矶闪电·橄榄1号位

洛杉矶闪电&#xff08;英语&#xff1a;Los Angeles Chargers&#xff09;&#xff0c;又译“洛杉磯衝鋒者”。是一支位于加利福尼亚州洛杉矶郡英格尔伍德的职业美式橄榄球球队&#xff0c;现为美国橄榄球联合会西区成员之一。该队曾于1961年搬迁到圣地亚哥而改叫圣地亚哥电光…...

4.7 Python设置代码格式

随着你编写的程序越来越长&#xff0c;有必要了解一些代码格式设置约定。请花时让你的代码尽可能易于阅读&#xff1b;让代码易于阅读有助于你掌握程序是做什么的,也可以帮助他人理解你编写的代码。为确保所有人编写的代码的结构都大致一致&#xff0c;Python程序员都遵循一些格…...

Zabbix 构建监控告警平台(五)

Zabbix 自动发现Zabbix 自动注册1.Zabbix 自动发现 1.1前言 为了满足监控企业成千上万台服务器&#xff0c;因此我们需要使用Zabbix批量监控来实现。自动发现和自动注册。 1.2zabbix-server &#xff08;一&#xff09;1、创建自动发现规则 在“配置”->“自动发现”->“…...

2023关键词:挑战

未失踪人口回归… 好久不见&#xff0c;不经意间拖更2个多月。今天周末&#xff0c;外面淅淅沥沥下着小雨&#xff0c;这种窝在床上的时刻最适合写点东西了。 但是建议大家在办公或者写博客的时候尽量还是端正坐姿&#xff0c;我就是因为喜欢这样靠在床背上&#xff0c;长时间…...

Wifi wpa_supplicant 到驱动的联系

同学,别退出呀,我可是全网最牛逼的 WIFI/BT/GPS/NFC分析博主,我写了上百篇文章,请点击下面了解本专栏,进入本博主主页看看再走呗,一定不会让你后悔的,记得一定要去看主页置顶文章哦。 从framework到wpa_supplicant的适配层,其中framework部分需要了注意的是wifiservic…...

【状态估计】基于二进制粒子群优化 (BPSO) 求解最佳 PMU优化配置研究【IEEE30、39、57、118节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

python 将 .pdf 文件转为 .md

环境准备 pip install aspose-words 代码 doc aw.Document(r"pdf 文件路径\xxx.pdf") doc.save("Output.md") 来源&#xff1a;https://products.aspose.com/words/zh/python-net/conversion/...

【C语言】操作符详解

每天一篇博客&#xff0c;卷死各位。 文章目录前言1. 算术操作符2. 移位进制位的表示移位操作符1. 》--左移操作符2. 《--右移操作符3.位操作符4.赋值操作符5.单目操作符6.关系操作符7. 逻辑操作符8.条件操作符9.逗号操作符总结前言 在c语言学习中操作符尤为重要&#xff0c;而…...

微信小程序 学生选课系统--nodejs+vue

系统分为学生和管理员&#xff0c;教师三个角色 学生小程序端的主要功能有&#xff1a; 1.用户注册和登陆系统 2.查看选课介绍信息 3.查看查看课程分类 4.查看课程详情&#xff0c;在线选课&#xff0c;提交选课信息 5.在线搜索课程信息 6.用户个人中心修改个人资料 7.用户查看…...

leaflet 加载geojson文件并显示图形(示例代码051)

第051个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载geojson文件,将图形显示在地图上。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意如果OpenStreetMap无法加载,请加载其他来练习 文章目录 示例效果配置方式示例源代码(…...

【Kafka】ZK和Kafka集群的安装和配置

一、集群环境说明1. 虚拟机&#xff1a;192.168.223.101/103/1052. 系统版本&#xff1a;CentOS 7.93. JDK版本&#xff1a;11.0.18.0.14. Zookeeper版本&#xff1a;3.7.15. Kafka版本&#xff1a;2.13-2.8.2备注&#xff1a;无论是ZK&#xff0c;还是Kafka&#xff0c;都需要…...

并发编程出现的问题以及解决方式

解决并发编程出现的问题基于java内存模式的设计出现的问题基于java内存模式的设计&#xff0c;多线程操作一些共享的数据时&#xff0c;出现以下三个问题&#xff1a;1.不可见性问题&#xff1a;多个线程同时在各自的工作内存对共享数据进行操作&#xff0c;彼此之间不可见。操…...

[ linux ] linux 命令英文全称及解释

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】&#x1f389;点赞➕评论➕收藏 养成习…...

C++11新特性

文章目录说在前面花括号{}初始化new的列表初始化STL相关容器的列表初始化相关语法格式容器列表初始化的底层原理forward_list和array与类型相关的新特性decltype左值引用和右值引用什么是左值&#xff0c;什么是右值左值和右值的本质区别右值引用如何理解右值引用std::move移动…...

【宝塔部署SpringBoot前后端不分离项目】含域名访问部署、数据库、反向代理、Nginx等配置

一定要弄懂项目部署的方方面面。当服务器上部署的项目过多时&#xff0c;端口号什么时候该放行、什么时候才会发生冲突&#xff1f;多个项目使用redis怎么防止覆盖&#xff1f;Nginx的配置会不会产生站点冲突&#xff1f;二级域名如何合理配置&#xff1f;空闲的时候要自己用服…...

从0到1一步一步玩转openEuler--11 openEuler基础配置-设置磁盘调度算法

11 openEuler基础配置-设置磁盘调度算法 文章目录11 openEuler基础配置-设置磁盘调度算法11.1 设置磁盘调度算法11.1.1 临时修改调度策略11.1.2 永久设置调度策略11.1 设置磁盘调度算法 本节介绍如何设置磁盘调度算法。 11.1.1 临时修改调度策略 例如将所有IO调度算法修改为…...

河道治理漂浮物识别监测系统 yolov7

河道治理漂浮物识别监测系统通过yolov7网络模型深度视觉分析技术&#xff0c;河道治理漂浮物识别监测算法模型实时检测着河道水面是否存在漂浮物、水浮莲以及生活垃圾等&#xff0c;识别到河道水面存在水藻垃圾等漂浮物&#xff0c;立即抓拍存档预警。You Only Look Once说的是…...

微信小程序 java ssm Springboot学生作业提交管理系统

系统具有良好的集成性&#xff0c;提供标准接口&#xff0c;以实现与其他相关系统的功能和数据集成。开放性好&#xff0c;便于系统的升级维护、以及与各种信息系统进行集成。功能定位充分考虑平台服务对象的需求。 一个微信小程序由.js、.json、.wxml、.wxss四种文件构成&…...

实战项目-课程潜在会员用户预测(朴素贝叶斯&神经网络)

目录1、背景介绍2、朴素贝叶斯2.1 模型介绍2.2 模型实现3、人工神经网络1、背景介绍 目标&#xff1a;将根据用户产生的数据对课程潜在的会员用户&#xff08;可能产生购买会员的行为&#xff09;进行预测。 平台的一位注册用户是否购买会员的行为应该是建立在一定背景条件下…...

ESP32设备驱动-定时器与定时器中断

定时器与定时器中断 文章目录 定时器与定时器中断1、ESP32定时器介绍2、定时器相关API介绍3、软件准备4、硬件准备3、代码实现有时需要按时发生某些事情,这就是计时器和计时器中断发挥作用的地方。 定时器是一种中断。 它就像一个简单的时钟,用于测量和控制时间事件,提供精确…...

【JavaScript 逆向】安居客滑块逆向分析

声明本文章中所有内容仅供学习交流&#xff0c;相关链接做了脱敏处理&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01;案例目标验证码&#xff1a;aHR0cHM6Ly93d3cuYW5qdWtlLmNvbS9jYXB0Y2hhLXZlcmlmeS8/Y2FsbGJhY2s9c2hpZWxkJmZyb209YW50aXNwYW0以上均做了脱敏处…...

【STM32】【HAL库】遥控关灯1主机

相关连接 【STM32】【HAL库】遥控关灯0 概述 【STM32】【HAL库】遥控关灯1主机 【STM32】【HAL库】遥控关灯2 分机 【STM32】【HAL库】遥控关灯3 遥控器 需求 主机需要以下功能: 接收来自物联网平台的命令发送RF433信号给从机接收RF433信号和红外信号驱动舵机动作 方案设计…...

Java 初始化块

文章目录1、初识初始化块2、实例初始化块和构造器3、类初始化块1、初识初始化块 Java 使用构造器来对单个对象进行初始化操作&#xff0c;使用构造器先完成对整个 Java 对象的状态初始化&#xff0c;然后将 Java 对象返回给程序&#xff0c;从而让该 Java 对象的信息更加完整。…...

超详细讲解长度受限制的字符串函数(保姆级教程!!!)

超详细讲解长度受限制的字符串函数&#xff08;保姆级教程&#xff01;&#xff01;&#xff01;&#xff09;长度受限制的字符串函数strncpy函数strncpy函数的使用strncpy函数的模拟实现strncat函数strncat函数的使用strncat函数的模拟实现strncmp函数strncmp函数的使用strncm…...

【c#】c#常用小技巧方法整理(4)——cmd命令提示符,c#调用cmd

CMD命令是一种命令提示符&#xff0c;CMD是command的缩写&#xff0c;位于系统System32的目录下&#xff0c;是大多数Windows操作系统中可用的命令行解释器应用程序。用于执行输入的命令。其中大多数命令通过脚本和批处理文件自动执行任务&#xff0c;执行高级管理功能&#xf…...

在项目中遇到的关于form表单的问题

前言 以下内容都是基于element Plus 和 vue3 一个form-item校验两个下拉框 有时候不可避免会遇到需要一个form-item校验两个下拉框的情况&#xff0c;比如&#xff1a; 这种情况下传统的校验已经无法实现&#xff0c;需要通过form表单提供的自定义校验来实现。以上面的必填…...

德国奔驰、博世和保时捷的员工年薪有多少?

点击 欧盟IT那些事 关注我们公告&#xff1a;因企鹅审核规定&#xff0c;本公众号从《德国IT那些事》更名为《欧盟IT那些事》。从职场新人到总裁&#xff0c;一个个盘。位于德国斯图加特的梅赛德斯-奔驰集团及其子公司梅赛德斯-奔驰是世界最知名的汽车制造商之一。奔驰车代表着…...

网站建设的概念/网站建设技术托管

展开全部回答不能插入代码格式&#xff0c;比较乱。e68a843231313335323631343130323136353331333433633433我截图给你看吧。package com.test;import javax.swing.*;import java.awt.*;public class DrawTest extends JFrame {public static void main(String[] args) {DrawTe…...

做企业网站广州/微信广告怎么投放

首先&#xff0c;我们需要在linux的系统客户机也要安装openssh-server 基本语法ssh 用户名iP例如&#xff0c;ssh welldone192.168.188.130使用ssh访问&#xff0c;如访问出现错误。可查看是否有该文件~/.ssh/known_ssh尝试删除该文件解决. 登出登出命令&#xff1a;exit或者l…...

上海史特做网站多少钱/全网seo

需要用到的API action&#xff1a;服务器上传地址 max-count&#xff1a;最大选择图片的数量 form-data&#xff1a;上传额外携带的参数 name&#xff1a;上传文件的字段名&#xff0c;供后端获取使用第一种&#xff1a;选择图片后&#xff0c;直接上传 <template><vi…...

辽宁网站建设找哪家/seo关键字排名

首先介绍Web服务器是什么Web服务器一般指网站服务器&#xff0c;是指驻留于因特网上某种类型计算机的程序&#xff0c;可以向浏览器等Web客户端提供文档&#xff0c;我们可以放置网站文件&#xff0c;让全世界浏览&#xff1b;可以放置数据文件&#xff0c;让全世界下载 常见的…...

wordpress 显示文章作者/数据分析师就业前景

5个月的线上销售业绩&#xff0c;几乎占据了黄古林全年电商销售额的90%。 这是一个强季节性产品。4月到8月是凉席在电商平台的销售旺季&#xff0c;也是黄古林一年的爆发节点。在此之前&#xff0c;它的销售集中在夏季最热的月份&#xff0c;通过自营门店、入驻超市&#xff0…...

长沙中小企业网站建设/99个创意营销方案

Ansible-playbook tomcat部署#目录树结构如下&#xff1a;[root192 roles]# tree tomcat tomcat ├── defaults ├── files │ └── apache-tomcat-7.0.63.zip ├── handlers │ └── main.yml ├── meta ├── tasks │ └── main.yml ├── templates …...