Android--Jetpack--Lifecycle详解

富贵本无根,尽从勤里得

一,定义

Lifecycle 是一个具备宿主生命周期感知能力的组件。它持有组件(Activity/Fragment)生命周期状态信息,并且允许其观察者监听宿主生命周期状态变化。

顾名思义,Lifecycle的主要作用其实就是帮助我们监听Activity或者Fragment的生命周期,不需要我们自己去定义回调接口来监听了,这样就使我们的代码更加简洁,逻辑更加清晰。

二,角色介绍

1,Lifecycle(生命周期) :一个核心抽象类,用于存储有关组件(如 activity/fragment )的生命周期状态的信息,并允许其他对象观察此状态。继承该类的子类,表示本身是一个 具有Android生命周期特性的对象。

2,LifecycleOwner:核心接口,Lifecycle 持有者,该接口的实现类表示能够为外部提供Lifecycle实例。具有 Android 生命周期的类。这些事件可以被自定义组件用来处理生命周期的变化,而不需要在 Activity/Fragment 中实现任何代码。

3,LifecycleRegistry:核心类,Lifecycle 的实现类,可以处理多个观察者。实现 Lifecycle 定义生命周期观察订阅,生命周期查询的方法。还实现了架构中,生命周期变化时触发的自身状态处理和相关对观察者的订阅回调的逻辑。

4,LifecycleObserver:观察者,将一个类标记为生命周期观察者。实现该接口的类,通过注解的方式,可以通过被 LifecycleOwner 类的 addObserver() 方法注册,LifecycleObserver 便可以观察到 LifecycleOwner 的生命周期事件。

5,State :当前生命周期所处的状态。

6,Event :当前生命周期改变对应的事件。从框架和 Lifecycle 类分派的生命周期事件。这些事件对应到 activity/fragment 中的回调事件。

三,基本使用

第一张使用方式非常简单:

1,添加依赖:

implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
implementation "androidx.lifecycle:lifecycle-common:2.5.1"

2,自定义一个类,这个类就是观察者,实现上面我们提到的LifecycleObserver 接口

定义方法,实现需要监控的生命周期,最主要的是注解

 @OnLifecycleEvent

以及上面提到的生命周期所处的状态:

public class YuanZhenLifecycleObserver implements LifecycleObserver {@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)void onCreate(){System.out.println("yz-----onCreate");}@OnLifecycleEvent(Lifecycle.Event.ON_START)void onStart(){System.out.println("yz-----onStart");}@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)void onResume(){System.out.println("yz-----onResume");}@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)void onPause(){System.out.println("yz-----onPause");}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)void onStop(){System.out.println("yz-----onStop");}@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)void onDestory(){System.out.println("yz-----onDestory");}}

 3,在需要被观察的宿主中,注册刚刚我们创建的观察者:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getLifecycle().addObserver(new YuanZhenLifecycleObserver());View viewById = findViewById(R.id.txt);viewById.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent =new Intent(MainActivity.this,SecondActivity.class);startActivity(intent);finish();}});}}

SecondActivity代码如下:

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

最后,运行后点击按钮,输出如下日志:

 至此,MainActivity的生命周期,就被我们轻松的观察到了。

第二种实现方式:

上一种实现方式方法已经过时了,所以我们推荐这种实现方式,直接实现接口DefaultLifecycleObserver 

然后我们重写它的生命周期方法即可:

public class YuanZhenFullObserver implements DefaultLifecycleObserver {@Overridepublic void onCreate(@NonNull LifecycleOwner owner) {DefaultLifecycleObserver.super.onCreate(owner);System.out.println("yz-----onCreate");}@Overridepublic void onStart(@NonNull LifecycleOwner owner) {DefaultLifecycleObserver.super.onStart(owner);System.out.println("yz-----onStart");}@Overridepublic void onResume(@NonNull LifecycleOwner owner) {DefaultLifecycleObserver.super.onResume(owner);System.out.println("yz-----onResume");}@Overridepublic void onPause(@NonNull LifecycleOwner owner) {DefaultLifecycleObserver.super.onPause(owner);System.out.println("yz-----onPause");}@Overridepublic void onStop(@NonNull LifecycleOwner owner) {DefaultLifecycleObserver.super.onStop(owner);System.out.println("yz-----onStop");}@Overridepublic void onDestroy(@NonNull LifecycleOwner owner) {DefaultLifecycleObserver.super.onDestroy(owner);System.out.println("yz-----onDestroy");}
}

然后再MainActivity使用:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getLifecycle().addObserver(new YuanZhenFullObserver());View viewById = findViewById(R.id.txt);viewById.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent =new Intent(MainActivity.this,SecondActivity.class);startActivity(intent);finish();}});}}

运行后输出:

使用方式都非常的简单高效。

四,基本原理

从上面的使用中我们就可以看出,lifecycle显然是使用了观察者模式,如果对于观察者模式不清楚的,建议看下文章Android设计模式--观察者模式-CSDN博客

 我们看源码,只能是先从使用入手:

getLifecycle().addObserver(new YuanZhenFullObserver());

通过addObserver方法,我们找到了Lifecycle这个抽象类:

public abstract class Lifecycle {//使用的入口@MainThreadpublic abstract void addObserver(@NonNull LifecycleObserver observer);@MainThreadpublic abstract void removeObserver(@NonNull LifecycleObserver observer);。。。。}

它的实现类LifecycleRegistry 中addObserver方法:

@Override
public void addObserver(@NonNull LifecycleObserver observer) {enforceMainThreadIfNeeded("addObserver");//判断当前的生命周期,将当前生命周期保存State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;//将YuanZhenLifecycleObserver这个观察者对象保存起来ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);if (previous != null) {return;}//获取到当前的被观察者 也就是MainActivityLifecycleOwner lifecycleOwner = mLifecycleOwner.get();if (lifecycleOwner == null) {// it is null we should be destroyed. Fallback quicklyreturn;}boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;//计算当前生命周期State targetState = calculateTargetState(observer);mAddingObserverCounter++;while ((statefulObserver.mState.compareTo(targetState) < 0&& mObserverMap.contains(observer))) {pushParentState(statefulObserver.mState);final Event event = Event.upFrom(statefulObserver.mState);if (event == null) {throw new IllegalStateException("no event up from " + statefulObserver.mState);}statefulObserver.dispatchEvent(lifecycleOwner, event);popParentState();// mState / subling may have been changed recalculatetargetState = calculateTargetState(observer);}if (!isReentrance) {// we do sync only on the top level.sync();}mAddingObserverCounter--;
}

上面的 LifecycleOwner lifecycleOwner = mLifecycleOwner.get();是怎么来的呢?

再MainActivity中使用getLifecycle()方法,就进入到了它的父类ComponentActivity:

public class ComponentActivity extends androidx.core.app.ComponentActivity implementsContextAware,LifecycleOwner,ViewModelStoreOwner,HasDefaultViewModelProviderFactory,SavedStateRegistryOwner,OnBackPressedDispatcherOwner,ActivityResultRegistryOwner,ActivityResultCaller {//创建LifecycleRegistry 实例private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);//获取到创建的LifecycleRegistry 实例@NonNull@Overridepublic Lifecycle getLifecycle() {return mLifecycleRegistry;}@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {// Restore the Saved State first so that it is available to// OnContextAvailableListener instancesmSavedStateRegistryController.performRestore(savedInstanceState);mContextAwareHelper.dispatchOnContextAvailable(this);super.onCreate(savedInstanceState);//创建一个透明的fragmentReportFragment.injectIfNeededIn(this);if (mContentLayoutId != 0) {setContentView(mContentLayoutId);}}。。。。}

ComponentActivity实现了LifeCyclerOwern接口,在ComponentActivity这个类中,创建了LifecycleRegistry,并将它本省传递给了LifecycleRegistry。

在这个类的onCreate方法中,有一个非常重要的方法,ReportFragment.injectIfNeededIn(this);它创建了一个透明的fragment。我们看看这个fragment里面干了什么。

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
public class ReportFragment extends android.app.Fragment {private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle"+ ".LifecycleDispatcher.report_fragment_tag";public static void injectIfNeededIn(Activity activity) {if (Build.VERSION.SDK_INT >= 29) {//注册回调LifecycleCallbacks.registerIn(activity);}//绑定fragmentandroid.app.FragmentManager manager = activity.getFragmentManager();if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();manager.executePendingTransactions();}}@SuppressWarnings("deprecation")static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {if (activity instanceof LifecycleRegistryOwner) {//如果activity实现了LifecycleOwner接口 调用handleLifecycleEvent((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);return;}if (activity instanceof LifecycleOwner) {Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();if (lifecycle instanceof LifecycleRegistry) {((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);}}}static ReportFragment get(Activity activity) {return (ReportFragment) activity.getFragmentManager().findFragmentByTag(REPORT_FRAGMENT_TAG);}private ActivityInitializationListener mProcessListener;private void dispatchCreate(ActivityInitializationListener listener) {if (listener != null) {listener.onCreate();}}private void dispatchStart(ActivityInitializationListener listener) {if (listener != null) {listener.onStart();}}private void dispatchResume(ActivityInitializationListener listener) {if (listener != null) {listener.onResume();}}@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);dispatchCreate(mProcessListener);dispatch(Lifecycle.Event.ON_CREATE);}@Overridepublic void onStart() {super.onStart();dispatchStart(mProcessListener);dispatch(Lifecycle.Event.ON_START);}@Overridepublic void onResume() {super.onResume();dispatchResume(mProcessListener);dispatch(Lifecycle.Event.ON_RESUME);}@Overridepublic void onPause() {super.onPause();dispatch(Lifecycle.Event.ON_PAUSE);}@Overridepublic void onStop() {super.onStop();dispatch(Lifecycle.Event.ON_STOP);}@Overridepublic void onDestroy() {super.onDestroy();dispatch(Lifecycle.Event.ON_DESTROY);// just want to be sure that we won't leak reference to an activitymProcessListener = null;}private void dispatch(@NonNull Lifecycle.Event event) {if (Build.VERSION.SDK_INT < 29) {// Only dispatch events from ReportFragment on API levels prior// to API 29. On API 29+, this is handled by the ActivityLifecycleCallbacks// added in ReportFragment.injectIfNeededIndispatch(getActivity(), event);}}void setProcessListener(ActivityInitializationListener processListener) {mProcessListener = processListener;}interface ActivityInitializationListener {void onCreate();void onStart();void onResume();}// this class isn't inlined only because we need to add a proguard rule for it (b/142778206)// In addition to that registerIn method allows to avoid class verification failure,// because registerActivityLifecycleCallbacks is available only since api 29.@RequiresApi(29)static class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks {static void registerIn(Activity activity) {activity.registerActivityLifecycleCallbacks(new LifecycleCallbacks());}@Overridepublic void onActivityCreated(@NonNull Activity activity,@Nullable Bundle bundle) {}@Overridepublic void onActivityPostCreated(@NonNull Activity activity,@Nullable Bundle savedInstanceState) {dispatch(activity, Lifecycle.Event.ON_CREATE);}@Overridepublic void onActivityStarted(@NonNull Activity activity) {}@Overridepublic void onActivityPostStarted(@NonNull Activity activity) {dispatch(activity, Lifecycle.Event.ON_START);}@Overridepublic void onActivityResumed(@NonNull Activity activity) {}@Overridepublic void onActivityPostResumed(@NonNull Activity activity) {dispatch(activity, Lifecycle.Event.ON_RESUME);}@Overridepublic void onActivityPrePaused(@NonNull Activity activity) {dispatch(activity, Lifecycle.Event.ON_PAUSE);}@Overridepublic void onActivityPaused(@NonNull Activity activity) {}@Overridepublic void onActivityPreStopped(@NonNull Activity activity) {dispatch(activity, Lifecycle.Event.ON_STOP);}@Overridepublic void onActivityStopped(@NonNull Activity activity) {}@Overridepublic void onActivitySaveInstanceState(@NonNull Activity activity,@NonNull Bundle bundle) {}@Overridepublic void onActivityPreDestroyed(@NonNull Activity activity) {dispatch(activity, Lifecycle.Event.ON_DESTROY);}@Overridepublic void onActivityDestroyed(@NonNull Activity activity) {}}
}

从这个fragment中我们可以看出,ReportFragment的生命周期函数都调用了dispatch()方法,而dispatch()方法则会判断Activity是否实现了LifecycleOwner接口,如果实现了该接口就调用LifecycleRegister的handleLifecycleEvent()。再来看看handleLifecycleEvent:

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {enforceMainThreadIfNeeded("handleLifecycleEvent");moveToState(event.getTargetState());
}
private void moveToState(State next) {if (mState == next) {return;}if (mState == INITIALIZED && next == DESTROYED) {throw new IllegalStateException("no event down from " + mState);}mState = next;if (mHandlingEvent || mAddingObserverCounter != 0) {mNewEventOccurred = true;// we will figure out what to do on upper level.return;}mHandlingEvent = true;sync();mHandlingEvent = false;if (mState == DESTROYED) {mObserverMap = new FastSafeIterableMap<>();}
}private void sync() {LifecycleOwner lifecycleOwner = mLifecycleOwner.get();if (lifecycleOwner == null) {throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"+ "garbage collected. It is too late to change lifecycle state.");}while (!isSynced()) {mNewEventOccurred = false;// no need to check eldest for nullability, because isSynced does it for us.if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {backwardPass(lifecycleOwner);}Map.Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();if (!mNewEventOccurred && newest != null&& mState.compareTo(newest.getValue().mState) > 0) {forwardPass(lifecycleOwner);}}mNewEventOccurred = false;
}

事件发生的时候,先得到当前activity应该出现的下一个状态,

moveToState(next); mState = next;更新现在的状态

sync();

backwardPass(lifecycleOwner);逆推

forwardPass(lifecycleOwner);正推

看看这两个方法:

private void forwardPass(LifecycleOwner lifecycleOwner) {Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =mObserverMap.iteratorWithAdditions();while (ascendingIterator.hasNext() && !mNewEventOccurred) {Map.Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred&& mObserverMap.contains(entry.getKey()))) {pushParentState(observer.mState);final Event event = Event.upFrom(observer.mState);if (event == null) {throw new IllegalStateException("no event up from " + observer.mState);}observer.dispatchEvent(lifecycleOwner, event);popParentState();}}
}
private void backwardPass(LifecycleOwner lifecycleOwner) {Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> descendingIterator =mObserverMap.descendingIterator();while (descendingIterator.hasNext() && !mNewEventOccurred) {Map.Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();ObserverWithState observer = entry.getValue();while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred&& mObserverMap.contains(entry.getKey()))) {Event event = Event.downFrom(observer.mState);if (event == null) {throw new IllegalStateException("no event down from " + observer.mState);}pushParentState(event.getTargetState());observer.dispatchEvent(lifecycleOwner, event);popParentState();}}
}

大致原理请看下图:

然后就调用 observer.dispatchEvent(lifecycleOwner, event); 生成观察者适配器:

static class ObserverWithState {State mState;LifecycleEventObserver mLifecycleObserver;ObserverWithState(LifecycleObserver observer, State initialState) {//创建观察者adapter 并将观察者传入adapter mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);mState = initialState;}void dispatchEvent(LifecycleOwner owner, Event event) {State newState = event.getTargetState();mState = min(mState, newState);mLifecycleObserver.onStateChanged(owner, event);mState = newState;}
}

mLifecycleObserver.onStateChanged(owner, event);将状态的变化通知给了观察者,来看看具体实现:

class FullLifecycleObserverAdapter implements LifecycleEventObserver {private final FullLifecycleObserver mFullLifecycleObserver;private final LifecycleEventObserver mLifecycleEventObserver;FullLifecycleObserverAdapter(FullLifecycleObserver fullLifecycleObserver,LifecycleEventObserver lifecycleEventObserver) {mFullLifecycleObserver = fullLifecycleObserver;mLifecycleEventObserver = lifecycleEventObserver;}@Overridepublic void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {switch (event) {case ON_CREATE:mFullLifecycleObserver.onCreate(source);break;case ON_START:mFullLifecycleObserver.onStart(source);break;case ON_RESUME:mFullLifecycleObserver.onResume(source);break;case ON_PAUSE:mFullLifecycleObserver.onPause(source);break;case ON_STOP:mFullLifecycleObserver.onStop(source);break;case ON_DESTROY:mFullLifecycleObserver.onDestroy(source);break;case ON_ANY:throw new IllegalArgumentException("ON_ANY must not been send by anybody");}if (mLifecycleEventObserver != null) {mLifecycleEventObserver.onStateChanged(source, event);}}
}

FullLifecycleObserverAdapter 在创建时,会持有LifecycleOwner ,当调用onStateChanged时,会调用具体观察者LifecycleOwner 的具体生命周期方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/189549.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TA-Lib学习研究笔记(八)——Momentum Indicators 上

TA-Lib学习研究笔记&#xff08;八&#xff09;——Momentum Indicators 上 Momentum Indicators 动量指标&#xff0c;是最重要的股票分析指标&#xff0c;能够通过数据量化分析价格、成交量&#xff0c;预测股票走势和强度&#xff0c;大部分指标都在股票软件中提供。 1. A…

ChatGpt回答人工智能发展利大于弊的辩证论述

ChatGpt回答人工智能发展利大于弊的辩证论述 ​ 随着科技的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域展现出强大的潜力&#xff0c;引发了广泛的关注和讨论。在这场变革中&#xff0c;人们对于人工智能的发展是否对人类有益的争论也愈发激烈。本文将…

离散化算法总结

离散化是将大范围的数字映射到小范围的区间内&#xff0c;适用于稀疏的区间。 两个问题需要考虑&#xff1a; 1. 原数组中可能有重复元素&#xff0c;需要去重。 2. 如何算出离散化后的值&#xff08;离散化后保序&#xff0c;使用二分&#xff09;。 题目链接&#xff1a; …

水利安全监测方案——基于RTU200的解决方案

引言&#xff1a; 水资源是人类赖以生存的重要基础&#xff0c;对于保障水利系统安全运行以及应对自然灾害起着关键作用。为了实现水利安全监测的目标&#xff0c;我们提出了基于RTU200的解决方案。本方案将结合RTU200的可靠性、灵活性和高效性&#xff0c;为您打造一个全面的…

[笔记]dubbo发送接收

公司需要使用java技术栈接入一套自定义的通讯协议&#xff0c;所以参考下dubbo的实现原理。 consumer 主要使用ThreadlessExecutor实现全consumer的全双工通讯。consumer创建本次请求的requestId用于将response和request匹配。 然后分以下几步完成一次请求发送并接收结果&…

GlusterFS + 防火墙访问控制+提供NFS服务

一、安装GlusterFS centos: yum -y install centos-release-gluster yum -y install glusterfs glusterfs-server glusterfs-fuse glusterfs-rdma systemctl start glusterd.service #开启服务 systemctl enable glusterd.service #开机自启 systemctl sta…

Elasticsearch分词器--空格分词器(whitespace analyzer)

介绍 文本分析&#xff0c;是将全文本转换为一系列单词的过程&#xff0c;也叫分词。analysis是通过analyzer(分词器)来实现的&#xff0c;可以使用Elasticearch内置的分词器&#xff0c;也可以自己去定制一些分词器。除了在数据写入时将词条进行转换&#xff0c;那么在查询的时…

Spring 多数据源搭建

目录 前言 正文 1.Druid 介绍和使用 2.其他多数据源解决方案 总结 前言 对于复杂的业务和项目&#xff0c;可能在一个单体项目中存在需要连接多个数据库的情况。这时&#xff0c;就会使用到多数据源&#xff0c;实际中遇到的可能性比较大。 正文 如果一个项目中需要连…

@2023 中国家居家具行业数字化转型分析与案例解读|商派徐礼昭

作者&#xff1a;徐礼昭&#xff08;商派市场负责人&#xff0c;重构零售实验室负责人&#xff09; 中国的家居家具行业面临着市场竞争激烈、消费者需求多变等诸多挑战。为了应对这些挑战&#xff0c;许多品牌企业开始探索数字化转型的道路&#xff0c;以提升竞争力并满足消费…

机器学习笔记 - 如何在Python中对网格和点云进行体素化?

一、简述 本文主要是为了了解如何生成体素表示,体素之于3D就像像素之于2D。体素本质上是 3D 像素,但它们不是正方形,而是完美的立方体。 理论上,体素是复制现实的完美建模技术。 这里我们要了解四个广泛流行的 Python 库(Open3D、Trimesh、PyVista、pyntcloud )生成点云…

java游戏攻略资讯网站的设计与实现springboot+vue

游戏攻略网站分为管理员与用户两种角色。 管理员的功能包括登录&#xff0c;用户管理&#xff0c;游戏分类管理&#xff0c;游戏攻略管理&#xff0c;游戏资讯管理等。 登录功能&#xff1a;管理员需要登录进入系统后台。 用户管理&#xff1a;实现用户信息的查询&#xff0c;修…

Python 发送企业微信消息

下方代码实现功能 1、联接Sqlserver数据库&#xff0c;取出发送消息清单 2、根据appid,secret获取企业微信token 3、根据消息清单类型决定发送客户消息还是内部员工消息 4、更新发送消标记 5、创建发送定时任务 from datetime import datetime import time import threading fr…

掌握未来设计趋势,开启AutoCAD2020创新之旅!

随着科技的不断发展&#xff0c;设计行业也在迅速演进&#xff0c;为满足设计师们日益增长的需求&#xff0c;Autodesk AutoCAD2020应运而生。作为一款全球领先的设计软件&#xff0c;AutoCAD2020不仅拥有更加强大的功能和更高效的性能&#xff0c;还融入了一系列的智能化设计工…

nrm安装以及常用命令

做为开发者&#xff0c;我们经常会使用到淘宝镜像去安装一些包。基本上设置的都是cnpm这种。但是这一长串其实很难记住。这时&#xff0c;我们可以用nrm进行镜像的切换更为方便。 npm install -g cnpm --registryhttps://registry.npm.taobao.org 安装方法 npm install nrm …

python实现多线程并发测试并生成excel报告

目录 一、技术背景 二、技术实现 1、设计思路步骤: 2、完成的代码如下:

vue给table组件添加合计

在 Vue 3 中&#xff0c;你可以使用 v-on:click 事件监听器来处理点击事件&#xff0c;并将数据添加到表格的第一行。假设你正在使用 Element UI 的表格组件&#xff0c;并且你想要在点击事件中添加一个合计行&#xff0c;你可以按照以下方式进行&#xff1a; <template>…

在java中如何读取数据库中的内容

1月,2月,3月,4月,5月,6月,7月,8月,9月,10月,11月,12月 20 22 25 28 30 33 35 34 32 28 24 21 -8 8 10 15 18 -22 -24 -24 -21 -16 -50 -20 package bbb;import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement;p…

Kotlin(十三) 延迟初始化和密封类

对变量延迟初始化 延迟初始化使用的是lateinit关键字&#xff0c;它可以告诉Kotlin编译器&#xff0c;我会在晚些时候对这个变量进行初始化&#xff0c;这样就不用在一开始的时候将它赋值为null了。示例如下&#xff1a; class MainActivity : AppCompatActivity() {private …

网页开发 JS基础

目录 JS概述 基本语法 数据类型内置方法 DOM对象 查找标签 绑定事件 操作标签 jQuery 查找标签 绑定事件 操作标签 Ajax请求 数据接口 前后端分离 ajax的使用 JS概述 一门弱类型的编程语言,属于基于对象和基于原型的脚本语言. 1 直接编写<script>console…

香港专才计划(输入内地人才计划)申请条件?附官网和申请攻略、利弊!

香港专才计划&#xff08;输入内地人才计划&#xff09;申请条件&#xff1f;附官网和申请攻略、利弊&#xff01; 输入内地人才计划&#xff08;英语&#xff1a;Admission Scheme for Mainland Talents and Professionals (ASMTP)&#xff09;&#xff0c;俗称专才计划&#…