ReactNative 启动应用(2)

ReactNative 启动应用

简述

本节我们来看一下ReactNative在Android上启动Activity的流程,ReactNative在Android上也是一个Apk,它的实现全部都在应用层,所以它肯定也是符合我们Android应用的启动流程的,UI页面的载体也是一个Activity,然后启动JS引擎来加载index.js,执行javascript的代码,然后javascript通过Fabric渲染器和TurboModule执行到java代码,调用到最终的Native实现,本节我们就来看一下启动的这个过程。

Application启动

1.1 MainApplication.init
ReactNative的能力被包装为Package,Package里面包含一些Module,每个Module是一个子能力,后续介绍TurboModule的时候会介绍包加载的流程。

class MainApplication : Application(), ReactApplication {// 主要就是构建了DefaultReactNativeHost和ReactHostoverride val reactNativeHost: ReactNativeHost =object : DefaultReactNativeHost(this) {override fun getPackages(): List<ReactPackage> =// 这里加载了所有包PackageList(this).packages.apply {// Packages that cannot be autolinked yet can be added manually here, for example:// add(MyReactNativePackage())}override fun getJSMainModuleName(): String = "index"override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUGoverride val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLEDoverride val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED}// 详见1.2override val reactHost: ReactHostget() = getDefaultReactHost(applicationContext, reactNativeHost)override fun onCreate() {super.onCreate()SoLoader.init(this, false)if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {load()}}
}

1.2 getDefaultReactHost
调用ReactNativeHost.toReactHost构造ReactHost。

@OptIn(UnstableReactNativeAPI::class)
@JvmStatic
public fun getDefaultReactHost(context: Context,reactNativeHost: ReactNativeHost,
): ReactHost {require(reactNativeHost is DefaultReactNativeHost) {"You can call getDefaultReactHost only with instances of DefaultReactNativeHost"}//详见1.3return reactNativeHost.toReactHost(context)
}

1.3 toReactHost
调用了getDefaultReactHost

@UnstableReactNativeAPI
internal fun toReactHost(context: Context): ReactHost =// 详见1.4DefaultReactHost.getDefaultReactHost(context,packages,jsMainModuleName,bundleAssetName ?: "index",isHermesEnabled ?: true,useDeveloperSupport,)

1.4 getDefaultReactHost
初始化了JS引擎,加载了js代码,还构建了DefaultReactHostDelegate,最终会把这些信息封装到一个ReactHostImpl中,ReactHost建立了React和Activity一些交互的接口。

@OptIn(UnstableReactNativeAPI::class)
@JvmStatic
public fun getDefaultReactHost(context: Context,packageList: List<ReactPackage>,jsMainModulePath: String = "index",jsBundleAssetPath: String = "index",isHermesEnabled: Boolean = true,useDevSupport: Boolean = ReactBuildConfig.DEBUG,cxxReactPackageProviders: List<(ReactContext) -> CxxReactPackage> = emptyList(),
): ReactHost {// 构建ReactHostImplif (reactHost == null) {// 创建jsBundleLoader,这个是用来执行JS代码的val jsBundleLoader =JSBundleLoader.createAssetLoader(context, "assets://$jsBundleAssetPath", true)// 创建JS引擎val jsRuntimeFactory = if (isHermesEnabled) HermesInstance() else JSCInstance()val defaultTmmDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder()cxxReactPackageProviders.forEach { defaultTmmDelegateBuilder.addCxxReactPackage(it) }// 构建DefaultReactHostDelegateval defaultReactHostDelegate =DefaultReactHostDelegate(jsMainModulePath = jsMainModulePath,jsBundleLoader = jsBundleLoader,reactPackages = packageList,jsRuntimeFactory = jsRuntimeFactory,turboModuleManagerDelegateBuilder = defaultTmmDelegateBuilder)val componentFactory = ComponentFactory()DefaultComponentsRegistry.register(componentFactory)// 创建ReactHostImpl,详见1.5reactHost =ReactHostImpl(context,defaultReactHostDelegate,componentFactory,true /* allowPackagerServerAccess */,useDevSupport,).apply {jsEngineResolutionAlgorithm =if (isHermesEnabled) {JSEngineResolutionAlgorithm.HERMES} else {JSEngineResolutionAlgorithm.JSC}}}return reactHost as ReactHost
}

1.5 ReactHostImpl
构建了一个DevSupportManager。

public ReactHostImpl(Context context,ReactHostDelegate delegate,ComponentFactory componentFactory,Executor bgExecutor,Executor uiExecutor,boolean allowPackagerServerAccess,boolean useDevSupport) {mContext = context;mReactHostDelegate = delegate;mComponentFactory = componentFactory;mBGExecutor = bgExecutor;mUIExecutor = uiExecutor;mQueueThreadExceptionHandler = ReactHostImpl.this::handleHostException;mMemoryPressureRouter = new MemoryPressureRouter(context);mAllowPackagerServerAccess = allowPackagerServerAccess;mUseDevSupport = useDevSupport;// debug版本和release版本,分别构建不同的SupportManagerif (mUseDevSupport) {mDevSupportManager =new BridgelessDevSupportManager(ReactHostImpl.this, mContext, mReactHostDelegate.getJsMainModulePath());} else {mDevSupportManager = new ReleaseDevSupportManager();}
}

Application中主要是初始化了一些React的对象,主要就是一个ReactHostImpl,ReactHostImpl里面持有了JS代码和引擎,以及要加载的包信息等等。

Activity启动

2.1 ReactActivity.onCreate
调了ReactActivityDelegate的onCreate

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 详见2.2mDelegate.onCreate(savedInstanceState);
}

2.2 ReactActivityDelegate.onCreate
构建ReactDelegate,会根据flag构建ReactDelegate传入不同的参数,我们跟新架构的路径。
ReactDelegate会持有ReactHost或者ReactNativeHost,新架构是前者,老架构师后者。

public void onCreate(Bundle savedInstanceState) {String mainComponentName = getMainComponentName();final Bundle launchOptions = composeLaunchOptions();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isWideColorGamutEnabled()) {mActivity.getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);}if (ReactFeatureFlags.enableBridgelessArchitecture) {// 详见2.3mReactDelegate =new ReactDelegate(getPlainActivity(), getReactHost(), mainComponentName, launchOptions);} else {mReactDelegate =new ReactDelegate(getPlainActivity(),getReactNativeHost(),mainComponentName,launchOptions,isFabricEnabled()) {@Overrideprotected ReactRootView createRootView() {ReactRootView rootView = ReactActivityDelegate.this.createRootView();if (rootView == null) {rootView = super.createRootView();}return rootView;}};}if (mainComponentName != null) {// 详见2.3loadApp(mainComponentName);}
}

2.3 ReactActivityDelegate.loadApp
构建根View,配置给Activity。

protected void loadApp(String appKey) {// 详见2.4mReactDelegate.loadApp(appKey);getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}

2.4 ReactDelegate.loadApp
这里一样有两套逻辑,新架构一套老架构一套,我们还是看新架构的流程。
这里构建了一个ReactSurfaceImpl,ReactSurfaceImpl里面会持有一个ReactSurfaceView,ReactSurfaceView是一个FrameLayout的子类,作为根View。
然后调用了mReactSurface.start来初始化。

public void loadApp(String appKey) {// With Bridgeless enabled, create and start the surfaceif (ReactFeatureFlags.enableBridgelessArchitecture) {if (mReactSurface == null) {// 构建了一个ReactSurfaceImpl和ReactSurfaceView,ReactSurfaceImpl持有ReactSurfaceView  // ReactSurfaceView本质就是一个FrameLayoutmReactSurface = mReactHost.createSurface(mActivity, appKey, mLaunchOptions);mActivity.setContentView(mReactSurface.getView());}// 启动ReactSurfaceImpl,详见2.5mReactSurface.start();} else {if (mReactRootView != null) {throw new IllegalStateException("Cannot loadApp while app is already running.");}mReactRootView = createRootView();mReactRootView.startReactApplication(getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);}
}

2.5 ReactSurfaceImpl.start
这里的Task是ReactNative自己写的一套逻辑,封装了异步调用的能力,功能类似于RXJava,就不详细看了,只要知道这是干啥用的就可以。
大致就是在mBGExecutor线程池里面调用getOrCreateStartTask返回的Task,然后等任务完成后回调getResult。
逻辑在getOrCreateStartTask里。

public TaskInterface<Void> start() {// 详见2.6return Task.call(this::getOrCreateStartTask, mBGExecutor).continueWithTask(Task::getResult);
}

2.6 ReactSurfaceImpl.getOrCreateStartTask
主要就是通过waitThenCallGetOrCreateReactInstanceTask来构建ReactInstance的Task

private Task<Void> getOrCreateStartTask() {final String method = "getOrCreateStartTask()";if (mStartTask == null) {log(method, "Schedule");mStartTask =// 调用waitThenCallGetOrCreateReactInstanceTask来构建ReactInstance,首次就会构建,后续使用缓存,详见2.7waitThenCallGetOrCreateReactInstanceTask().continueWithTask((task) -> {if (task.isFaulted()) {mReactHostDelegate.handleInstanceException(task.getError());// 如果出现异常则调用DestoryTask。return getOrCreateDestroyTask("getOrCreateStartTask() failure: " + task.getError().getMessage(),task.getError()).continueWithTask(destroyTask -> Task.forError(task.getError())).makeVoid();}return task.makeVoid();},mBGExecutor);}return mStartTask;
}

2.7 ReactSurfaceImpl.waitThenCallGetOrCreateReactInstanceTaskWithRetries
直接调用了waitThenCallGetOrCreateReactInstanceTaskWithRetries重载函数

@ThreadConfined("ReactHost")
private Task<ReactInstance> waitThenCallGetOrCreateReactInstanceTask() {// 调用重载函数,传入参数为重试次数,详见2.8return waitThenCallGetOrCreateReactInstanceTaskWithRetries(0, 4);
}

2.8 ReactSurfaceImpl.waitThenCallGetOrCreateReactInstanceTaskWithRetries
这里最终调用了getOrCreateReactInstanceTask来创建 创建ReactInstance的Task,也就是说其实最终是通过getOrCreateReactInstanceTask返回的Task里面的任务来创建ReactTask,其他的代码都是负责处理辅助逻辑,如失败重试,失败销毁,切换线程执行等。

@ThreadConfined("ReactHost")
private Task<ReactInstance> waitThenCallGetOrCreateReactInstanceTaskWithRetries(int tryNum, int maxTries) {final String method = "waitThenCallGetOrCreateReactInstanceTaskWithRetries";if (mReloadTask != null) {log(method, "React Native is reloading. Return reload task.");return mReloadTask;}if (mDestroyTask != null) {// 如果失败后重试次数没到最大重试次数,还可以重试boolean shouldTryAgain = tryNum < maxTries;if (shouldTryAgain) {log(method,"React Native is tearing down."+ "Wait for teardown to finish, before trying again (try count = "+ tryNum+ ").");return mDestroyTask.onSuccessTask((task) -> waitThenCallGetOrCreateReactInstanceTaskWithRetries(tryNum + 1, maxTries),mBGExecutor);}raiseSoftException(method,"React Native is tearing down. Not wait for teardown to finish: reached max retries.");}// 调用getOrCreateReactInstanceTask来创建ReactInstance,详见2.9return getOrCreateReactInstanceTask();
}

2.9 ReactSurfaceImpl.getOrCreateReactInstanceTask
ReactInstance代表着React的一个实例,里面持有了FabricUIManager,TurboModuleManager等,且提供了loadJSBundle执行JS代码,是React在Java侧最重要的管理类了。
这里最终调用了instance.loadJSBundle来执行JS代码。

@ThreadConfined("ReactHost")
private Task<ReactInstance> getOrCreateReactInstanceTask() {final String method = "getOrCreateReactInstanceTask()";log(method);return mCreateReactInstanceTaskRef.getOrCreate(() -> {log(method, "Start");ReactMarker.logMarker(ReactMarkerConstants.REACT_BRIDGELESS_LOADING_START, BRIDGELESS_MARKER_INSTANCE_KEY);// 获取JsBundleLoder,最终是通过这个来执行JS代码的,这个JsBundleLoader就是我们在Application初始化ReactHost的时候创建的那个。return getJsBundleLoader().onSuccess(task -> {// 前面Task完成后会进onSuccess,task.getResult可以拿到前面方法的返回值,就是JsBundleLoaderfinal JSBundleLoader bundleLoader = task.getResult();final BridgelessReactContext reactContext = getOrCreateReactContext();final DevSupportManager devSupportManager = getDevSupportManager();reactContext.setJSExceptionHandler(devSupportManager);log(method, "Creating ReactInstance");// 构建ReactInstance,这里初始化了很多内容,比较重要的有FabricUIManager,TurboModuleManagerfinal ReactInstance instance =new ReactInstance(reactContext,mReactHostDelegate,mComponentFactory,devSupportManager,mQueueThreadExceptionHandler,mUseDevSupport,getOrCreateReactHostInspectorTarget());mReactInstance = instance;instance.initializeEagerTurboModules();MemoryPressureListener memoryPressureListener =createMemoryPressureListener(instance);mMemoryPressureListener = memoryPressureListener;mMemoryPressureRouter.addMemoryPressureListener(memoryPressureListener);log(method, "Loading JS Bundle");// 执行JS代码,详见2.10instance.loadJSBundle(bundleLoader);// ...return new Result();},mBGExecutor).onSuccess(task -> {// ...流转生命周期return reactInstance;},mUIExecutor);});
}

2.10 ReactInstance.loadJSBundle
这里逻辑挺绕的,这里会调用JSBundleLoader的loadScript,JSBundleLoader是在1.4通过createAssetLoader创建的,是一个匿名内部类,里面就是调用了JSBundleLoaderDelegate.loadScriptFromAssets,JSBundleLoaderDelegate是loadscript的一个入参,是这里的匿名内部类,随意就是执行了这里的loadScriptFromAssets。

public void loadJSBundle(JSBundleLoader bundleLoader) {// Load the JS bundleSystrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstance.loadJSBundle");bundleLoader.loadScript(new JSBundleLoaderDelegate() {@Overridepublic void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously) {mBridgelessReactContext.setSourceURL(sourceURL);loadJSBundleFromFile(fileName, sourceURL);}@Overridepublic void loadSplitBundleFromFile(String fileName, String sourceURL) {loadJSBundleFromFile(fileName, sourceURL);}@Overridepublic void loadScriptFromAssets(//执行的是这,我们在编译后会将js打包到assets目录下,这里就是执行入口。AssetManager assetManager, String assetURL, boolean loadSynchronously) {mBridgelessReactContext.setSourceURL(assetURL);// 详见2.11loadJSBundleFromAssets(assetManager, assetURL);}@Overridepublic void setSourceURLs(String deviceURL, String remoteURL) {mBridgelessReactContext.setSourceURL(deviceURL);}});Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}public static JSBundleLoader createAssetLoader(final Context context, final String assetUrl, final boolean loadSynchronously) {return new JSBundleLoader() {@Overridepublic String loadScript(JSBundleLoaderDelegate delegate) {delegate.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);return assetUrl;}};
}

2.11 ReactInstance.loadJSBundleFromAssets
这个是native方法,映射到C++层是JReactInstance::loadJSBundleFromAssets。

void JReactInstance::loadJSBundleFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager,const std::string& assetURL) {const int kAssetsLength = 9; // strlen("assets://");auto sourceURL = assetURL.substr(kAssetsLength);auto manager = extractAssetManager(assetManager);// 加载asset内的文件,将结果存在scriptauto script = loadScriptFromAssets(manager, sourceURL);// 最终调用的C++层的ReactInstance::loadScriptinstance_->loadScript(std::move(script), sourceURL);
}

2.12 ReactInstance::loadScript
这里调用了JSCRuntime.evaluateJavaScript,这里就到了JSI到逻辑了,JSI是使用JS引擎提供的api封装的轻量级框架,用于提供Ojbect-C和JS或者C++和JS通信,我们这里就不继续深入了,后面会有专门一节介绍JSI。
这里调用JSI接口执行JS代码,就到了index.js了,后续index.js代码是怎么最终通知Native构建View以及显示的逻辑我们在Fabric渲染器章节再来介绍。

void ReactInstance::loadScript(std::unique_ptr<const JSBigString> script,const std::string& sourceURL) {
auto buffer = std::make_shared<BigStringBuffer>(std::move(script));
std::string scriptName = simpleBasename(sourceURL);runtimeScheduler_->scheduleWork([this,scriptName,sourceURL,buffer = std::move(buffer),weakBufferedRuntimeExecuter = std::weak_ptr<BufferedRuntimeExecutor>(bufferedRuntimeExecutor_)](jsi::Runtime& runtime) {try {SystraceSection s("ReactInstance::loadScript");bool hasLogger(ReactMarker::logTaggedMarkerBridgelessImpl);if (hasLogger) {ReactMarker::logTaggedMarkerBridgeless(ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());}// 调用JSCRuntime.evaluateJavaScript,这就到了JSI层了,我们这里暂时不继续看了,后面会有一节专门讲JSIruntime.evaluateJavaScript(buffer, sourceURL);if (hasLogger) {ReactMarker::logTaggedMarkerBridgeless(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());ReactMarker::logMarkerBridgeless(ReactMarker::INIT_REACT_RUNTIME_STOP);ReactMarker::logMarkerBridgeless(ReactMarker::APP_STARTUP_STOP);}if (auto strongBufferedRuntimeExecuter =weakBufferedRuntimeExecuter.lock()) {strongBufferedRuntimeExecuter->flush();}} catch (jsi::JSError& error) {jsErrorHandler_->handleFatalError(error);}});
}

小结

通过上面的介绍,我们知道了ReactNative的Android app是怎么启动并且最终执行到JS到index.js代码,中间我们跳过了一些逻辑,比如加载TruboModule包,且后面index.js执行后又是怎么通知到Native侧,让应用更新对应的View布局,以及JSI是怎么通过JS引擎提供的接口实现JS和C++层通信,这些我们会在后面的章节来介绍。

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

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

相关文章

易基因:Nat Commun:ATAC-seq等揭示恒河猴大脑高分辨率解剖区域的转录组和开放染色质图谱

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 恒河猴是神经科学研究中常用的模型动物&#xff0c;其大脑结构和功能与人类大脑相似。大脑中复杂的遗传网络是灵长类动物行为、认知和情感的基础&#xff0c;一直是神经科学的核心。大脑…

禾川SV-X2E A伺服驱动器参数设置——脉冲型

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff01;人工智能学习网站 前言&#xff1a; 大家好&#xff0c;我是上位机马工&#xff0c;硕士毕业4年年入40万&#xff0c;目前在一家自动化公司担任…

【Android】基础回顾--四大组件

1. 四大组件是什么&#xff1f; 四大组件&#xff1a;Activity、Service、BroadcastReceiver、ContentProvider。 2. 四大组件的生命周期和简单用法 Activity&#xff1a; 特殊情况下的生命周期&#xff1a; 典型的生命周期好像没什么可说的&#xff0c;主要说一下特殊情况…

基于Datawhale开源量化投资学习指南(11):LightGBM在量化选股中的优化与实战

1. 概述 在前几篇文章中&#xff0c;我们初步探讨了如何通过LightGBM模型进行量化选股&#xff0c;并进行了一些简单的特征工程和模型训练。在这一篇文章中&#xff0c;我们将进一步深入&#xff0c;通过优化超参数和实现交叉验证来提高模型的效果&#xff0c;并最终通过回测分…

C++ | Leetcode C++题解之第516题最长回文子序列

题目&#xff1a; 题解&#xff1a; class Solution { public:int longestPalindromeSubseq(string s) {int n s.length();vector<vector<int>> dp(n, vector<int>(n));for (int i n - 1; i > 0; i--) {dp[i][i] 1;char c1 s[i];for (int j i 1; j…

2-135 基于matlab的有限差分法计算电位分布

基于matlab的有限差分法计算电位分布&#xff0c;设置目标尺寸的矩形区域&#xff0c;设置矩形区域内的网格数量&#xff0c;根据网格位置在区域内设置电位&#xff0c;实现电位分布计算。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&#xff1a;2-135 基于matlab…

微信小程序的日期区间选择组件的封装和使用

组件化开发是一种将大型软件系统分解为更小、更易于管理和复用的独立模块或组件的方法。这种方法在现代软件开发中越来越受到重视&#xff0c;尤其是在前端开发领域。微信小程序的日期区间选择组件的使用 wxml 代码 <view><view bind:tap"chooseData">…

【Redis】内存淘汰策略

文章目录 什么是内存淘汰策略设置Redis最大内存执行内存淘汰策略的流程Redis的八大内存淘汰策略深入源码进行理解内存淘汰策略流程 什么是内存淘汰策略 Redis内存淘汰策略是指当Redis的内存使用达到其配置的最大内存限制&#xff08;maxmemory&#xff09;时&#xff0c;Redis…

论文笔记(五十)Segmentation-driven 6D Object Pose Estimation

Segmentation-driven 6D Object Pose Estimation 文章概括摘要1. 引言2. 相关工作3. 方法3.1 网络架构3.2 分割流3.3 回归流3.4 推理策略 4. 实验4.1 评估 Occluded-LINEMOD4.1.1 与最先进技术的比较4.1.2 不同融合策略的比较4.1.3 与人体姿态方法的比较 4.2 在YCB-Video上的评…

uniapp使用easyinput文本框显示输入的字数和限制的字数

uniapp使用easyinput文本框显示输入的字数和限制的字数 先上效果图&#xff1a; 整体代码如下&#xff1a; <template><view class"nameInfoContent"><uni-easyinput class"uni-mt-5" suffixIcon"checkmarkempty" v-model&quo…

【MyBatis源码】SqlSessionFactoryBuilder源码分析

文章目录 概述类结构从 InputStream 创建 SqlSessionFactoryXMLConfigBuilder构建ConfigurationXMLConfigBuilder初始化方法parse()方法parseConfiguration属性&#xff08;properties&#xff09; 概述 SqlSessionFactory 是 MyBatis 的核心接口之一&#xff0c;提供创建 Sql…

vue通过JSON文件生成WPML文件源码

可以使用封装的json解析器进行JSON数据获取&#xff0c;读取点的经度、维度、高程等数据&#xff0c;再使用对应的WPML文件生成函数使用该源码下载WPML文件&#xff08;固定WPML生成&#xff1a;js模板式生成大疆上云wpml文件&#xff08;含详细注释&#xff0c;已封装成函数&a…

(7) cuda异常处理

文章目录 上节概要异常处理代码 上节概要 上一节 block_width 64的时候&#xff0c;64644096 > 1024&#xff08;一个block里面最多只能有1024个线程&#xff0c;所以这里计算会有问题&#xff09; 异常处理 __FILE__: 编译器内部定义的一个宏。表示的是当前文件的文件…

【C++单调栈 贡献法】907. 子数组的最小值之和|1975

本文涉及的基础知识点 C单调栈 LeetCode907. 子数组的最小值之和 给定一个整数数组 arr&#xff0c;找到 min(b) 的总和&#xff0c;其中 b 的范围为 arr 的每个&#xff08;连续&#xff09;子数组。 由于答案可能很大&#xff0c;因此 返回答案模 109 7 。 示例 1&#x…

项目:Boost 搜索引擎

项目&#xff1a;Boost 搜索引擎 1、项目背景 公司&#xff1a;百度、360、搜狗、谷歌 …站内搜索&#xff1a;搜索的数据更垂直&#xff08;相关&#xff09;&#xff0c;数据量小 2、整体框架 3、技术栈和项目环境 技术栈&#xff1a;C/C C11&#xff0c;STL&#xff0c;jso…

error Unexpected mutation of “xxxxx“ prop

错误是在进行 eslint 检查的时候触发的&#xff0c;这个错误的原因是我们在子组件中改变了父组件传递过来的 props 解决方法一&#xff1a; 不改变父组件传递过来的 props&#xff0c;如果需要改变父组件传递过来的值&#xff0c;可以使用 defineModel() 进行接收值&#xff…

【零售和消费品&软件包】快递包装类型检测系统源码&数据集全套:改进yolo11-HSPAN

改进yolo11-EfficientHead等200全套创新点大全&#xff1a;快递包装类型检测系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.24 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展示的系统…

STM32第15章 RCC-使用HSE/HSI配置时钟

时间:2024.10.21-10.23 参考资料: 《零死角玩转STM32》“RCC-使用HSE/HIS配置时钟”章节 TIPS: 从前面的历程中我们知道,程序在启动的时候会执行汇编文件,汇编文件里会调用System_Init(固件库编程的函数),它里面会把时钟初始化成72M,因此前面我们在用固件库写程序的…

MSR寄存器独有的还是共享的

英特尔白皮书Volume 4: Model-Specific Registers 这一章列出了不同英特尔处理器系列的 MSR&#xff08;模型特定寄存器&#xff09;。所有列出的 MSR 都可以使用 RDMSR 和 WRMSR 指令进行读取和写入。MSR 的作用域定义了访问相同 MSR 的处理器集合&#xff0c;具体如下&#x…