【Android14 ShellTransitions】(七)Transition就绪

Transition.onTransactionReady的内容比较长,我们挑重点的部分逐段分析(跳过的地方并非不重要,而是我柿子挑软的捏)。

1 窗口绘制状态的流转以及显示SurfaceControl

注意我们这里的SurfaceControl特指的是WindowSurfaceController的mSurfaceControl,如果对这个不是很了解的,可以回顾一下之前写的关于SurfaceControl的文章:

【基础】2、Surface的创建【Android 12】 - 掘金 (juejin.cn)

接着分析代码:

在这里插入图片描述

先跳过Transition.commitVisibleActivities,看到首先是将Transition.mState置为STATE_PLAYING,这意味着动画马上就要执行了。

然后是为Transition的两个成员变量mStartTransaction以及mFinishTransaction赋值,mFinishTransaction不用多说,看到mStartTransaction被赋值为传参transaction,传参即我们上一篇分析中的在SyncGroup.finishNow创建的一个Transaction,局部变量merged:

在这里插入图片描述

一个“start transaction”和一个“finish transaction”,我按照个人的理解,举个例子说明一下,如果我们从ActivityA上启动了一个ActivityB:

1)、对于ActivityA来说,它相关的SurfaceControl(准确一点说则是WindowSurfaceController.mSurfaceControl)需要在动画结束的时候再隐藏,如果它在动画开始前就隐藏,那么就无法看到ActivityA的动画效果了(向右平移退出或者淡出之类的动画)。

2)、对于ActivityB来说,它相关的SurfaceControl需要在动画开始的时候就显示出来,如果它在动画开始的时候还没有显示,那么同样也无法看到ActivityB的动画效果了(向右平移进入或者淡入之类的动画)。

从以上分析可知,ActivityA和ActivityB相关的SurfaceControl可见性变化的时机是不同的,那么这个行为通过一次Transacton.apply是无法做到的,所以就需要两个Transaction,即“start transaction”和“finish transaction”。“start transaction”在动画开始前调用apply,用于在动画开始执行前提前将ActivityB进行显示,“finish transaction”则是在动画结束的时候调用apply,用于在动画结束的时候再将ActivityA隐藏。

最重要的是要弄清楚“start transaction”和“finish transaction”这两个Transaction调用apply方法的时机,在以后的Transition流程中会分析到。

再来看Transition.commitVisibleActivities方法的内容:

在这里插入图片描述

如该方法的注释所说,当前Transition已经准备好执行动画了,这里先让“start transaction”把相关需要显示的SurfaceControl显示出来。

Transition.mParticipants是参与动画的WindowContainer集合,那么这个方法就是遍历这个集合:

1)、调用ActivityRecord.commitVisibility设置相关ActivityRecord的为可见。

2)、调用ActivityRecord.commitFinishDrawing进一步设置相关SurfaceControl为可见。

ActivityRecord.commitVisibility方法内容比较多,主要是用来ActivityRecord的可见性,即其成员变量mVisible,除此之外还有很多别的逻辑,但是和我们要分析的Transition内容无关,只需要知道这里设置了ActivityRecord的可见性即可,不去多说。我们主要看下ActivityRecord.commitFinishDrawing:

在这里插入图片描述

很简单,为每一个child,即WindowState调用commitFinishDrawing方法:

在这里插入图片描述

1)、调用WindowStateAnimator.commitFinishDrawingLocked方法,继续将窗口对应的WindowStateAnimator的mDrawState,即绘制状态进行流转。

2)、调用WindowStateAnimator.prepareSurfaceLocked,设置SurfaceControl的可见性。

这两个方法都比较重要,我们接下来分别进行分析。

1.1 窗口绘制状态的流转

SurfaceControl最终的显示和窗口的绘制状态密切相关,所以我感觉这里有必要看一下WindowStateAnimator.mDrawState这个状态是如何切换的,并且我自己对这个窗口的绘制状态也是不求甚解,也希望借着这个机会了解一下。

先分析一下代码,回头再试着总结一下。

·1.1.1 WindowStateAnimator.commitFinishDrawingLocked

在这里插入图片描述

首先将WindowState.mDrawState设置为READY_TO_SHOW。

然后如果当前WindowStateAnimator相关的WindowState满足以下条件之一,则继续调用WindowStateAnimator.performShowLocked:

1)、没有对应的ActivityRecord,即是一个非Activity窗口:

activity == null

2)、有对应的ActivityRecord,并且此时已经可以显示窗口了:

activity.canShowWindows()

在这里插入图片描述

重要是就是看这个ActivityRecord的mSyncState是不是SYNC_STATE_WAITING_FOR_DRAW,如果是这个值,那么就说明这个ActivityRecord是处于动画中的。

但是有一个问题是,ActivityRecord的mSyncState是不会被设置为SYNC_STATE_WAITING_FOR_DRAW的,只有WindowState才会,那岂不是每次走到这里判断ActivityRecord是否drawn,都将一直是true。

3)、是一个TYPE_APPLICATION_STARTING类型的窗口,即SplashScreen或者Snapshot:

mWin.mAttrs.type == TYPE_APPLICATION_STARTING

总而言之,如果这个WindowState满足了绘制了条件,那么将继续调用WindowState.performShowLocked。

1.1.2 WindowState.performShowLocked

在这里插入图片描述

如果WindowStateAnimator.mDrawState不是READY_TO_SHOW,那么返回false,否则将其置为HAS_DRAWN,并且返回true,这将使得我们可以下一步继续调用WindowStateAnimator.prepareSurfaces方法。

从WindowStateAnimator.commitFinishDrawingLocked以及WindowState.performShowLocked这两个方法都能看到,窗口的绘制状态是循序渐进的,必须是状态A -> 状态B -> 状态C,不存在状态A直接到状态C之类的。

1.1.3 窗口绘制状态小结

首先是mDrawState在WindowStateAnimator的定义,以及几个取值:

在这里插入图片描述

结合着Activity启动的一般流程,我大致总结一下:

1)、NO_SURFACE:当没有Surface的就置为这个状态。

这个很好理解,一般窗口销毁相关的流程,会将WindowStateAnimator.mDrawState设置为NO_SURFACE,比如:

WindowState.removeImmediately

-> WindowStateAnimator.destroySurfaceLocked

-> WindowStateAnimator.destroySurface

此阶段没有窗口,也没有Surface。

2)、DRAW_PENDING:当Surface被创建之后,窗口被添加但还没有开始绘制之前,就会置为这个状态。在这个时期,Surface是隐藏的。这表明Surface正等待应用程序绘制窗口的内容。

当窗口被添加,接着App侧开始走measure、layout以及draw流程,在draw之前,会将窗口在WMS侧进行relayout,经过:

WMS.relayoutWindow

-> WMS.createSurfaceControl

-> WindowStateAnimator.createSurfaceLocked

-> WindowStateAnimator.resetDrawState

会将WindowStateAnimator.mDrawState设置为DRAW_PENDING。

这个流程我们也很熟悉,即之前分析创建WindowSurfaceController的SurfaceControl的流程。

此阶段窗口被添加但还没绘制出来,SurfaceControl也是隐藏的。

3)、COMMIT_DRAW_PENDING:当窗口的绘制操作完成,但是这个Surface还没有显示出来之前,状态会设置为此值。这个Surface会在下次layout过程中显示出来。

当窗口绘制完成,App侧调用ViewRootImpl.reportDrawFinished后,就会调用IWindowSession的对端,经过:

Session.finishDrawing

-> WMS.finishDrawingWindow

-> WindowState.finishDrawing

-> WindowStateAnimator.finishDrawingLocked

会将WindowStateAnimator.mDrawState设置为COMMIT_DRAW_PENDING。

此阶段窗口已经绘制完成,但是Surface由于一些原因还不能显示。

4)、READY_TO_SHOW:这个状态标识窗口的绘制操作已经提交,但Surface还没有真正显示。在一组窗口(例如属于同一个应用的多个窗口)准备显示时,系统会使用这个状态来延迟显示Surface,直到所有相关窗口都准备好一起显示。

首先我们看到在动画的流程中,窗口的绘制状态被设置为READY_TO_SHOW的流程为:

Transition.onTransactionReady

-> Transition.commitVisibleActivities

-> ActivityRecord.commitFinishDrawing

-> WindowState.commitFinishDrawing

-> WindowStateAnimator.commitFinishDrawingLocked

结合注释,我个人的理解是,绘制状态被置为READY_TO_SHOW,表明此窗口已经绘制完了,可以准备显示它的SurfaceControl了,但是它的SurfaceControl需要等待和其它的SurfaceContrl一起显示,或者说等待动画走到特定阶段才能显示,因此我们这里推迟其SurfaceControl的显示时间,将窗口的绘制状态设置为READY_TO_SHOW。

如果不考虑和其它窗口一起显示,那么我想在这一步就可以将绘制状态设置为HAS_DRAWN了,即READY_TO_SHOW这个状态值是不必要的。

5)、HAS_DRAWN:当窗口首次在屏幕上显示时,就会设置为此状态。

这个值在WindowState.performShowLocked方法中被设置,紧跟着WindowStateAnimator.commitFinishDrawingLocked方法。

严谨一点的话注释的说法其实是不准确的,当窗口绘制状态被设置为HAS_DRAWN的时候,只是说明SurfaceControl接下来可以显示了,但是SurfaceControl仍然没有显示,屏幕上是看不见的。

6)、总结一下,从以上分析可知,这些状态值不只涉及了窗口的绘制流程,还涉及了SurfaceControl的显示流程:

  • NO_SURFACE:没窗口,也没SurfaceControl。
  • DRAW_PENDING:有窗口,但没开始绘制。有SurfaceControl,但不能显示。
  • COMMIT_DRAW_PENDING,窗口刚刚绘制完,SurfaceControl还不能显示。
  • READY_TO_SHOW:窗口已经绘制完了,SurfaceControl可以显示了,但没必要,再等等。
  • HAS_DRAWN:窗口已经绘制完了,SurfaceControl也可以显示了。

1.2 显示SurfaceControl

回到WindowState.commitFinishDrawing,在调用WindowStateAnimator.commitFinishDrawingLocked将窗口的绘制状态走完后,接下来就是调用WindowStateAnimator.prepareSurfaceLocked来显示SurfaceControl了。

注意这个方法被调用的地方有两处:

在这里插入图片描述

还有一处调用的地方在WindowState.prepareSurfaces,这个是更通用的流程,但是动画流程下,则稍微不同,即我们分析的这个流程。

看代码:

在这里插入图片描述

我们只看和显示SurfaceControl相关的部分:

1)、如果窗口不在屏幕上,则调用WindowStateAnimator.hide -> WindowSurfaceController.hide来隐藏SurfaceControl。

2)、如果窗口在屏幕上,那么进一步判断窗口的绘制状态,只有窗口的绘制状态为HAS_DRAWN,才能继续调用WindowSurfaceController.showRobustly来显示SurfaceControl:

在这里插入图片描述

关键的就那一句,调用Transaction.show来显示相关SurfaceControl,但是要注意的是这里并没有调用Transaction.apply,所以这个时候窗口还是没有显示。

窗口的最终显示则是和这个传参Transaction对象有关,这个Transaction对象则是之前说的”start transaction“,那么这个Transaction的apply方法的调用时机则是跟Transition的流程相关,以后的分析会看到。

2 计算动画目标

这一节的内容是调用Transition.calculateTargets来计算动画的目标:

在这里插入图片描述

Transition的成员变量mTargets定义为:

在这里插入图片描述

之前收集到的动画参与者提升后的最终的动画目标,也就是说最终执行动画的主体并非是之前收集到的动画参与者,而是这一步用动画参与者计算得到的动画目标。

Transition.calculateTargets的内容为:

在这里插入图片描述

大致的内容为:

1)、创建一个Transition.Targets类型的局部变量targets,来收集动画目标。

2)、遍历Transition.mParticipants,从Transition.mChanges中取出对应的ChangeInfo对象放到Transition.Targets.mArray中,但是跳过WindowState类型的动画参与者,以及跳过那些根据ChangeInfo.hasChanged得出前后没有发生变化的动画参与者。

3)、调用Transition.tryPromote尝试提升targets中保存的动画目标的级别。

我们这一节主要来看下这个Transition.tryPromote。

”promote“,提升的动画目标在WindowContainer层级结构中的级别,这个逻辑之前在AppTransitionController.getAnimationTargets也用到了,思想都是类似的。比如一个Task中有两个ActivityRecord,并且这两个ActivityRecord要分别执行一段动画,也就是动画执行的主体是ActivityRecord。如果这两个ActivityRecord刚好都想向左平移同样的距离,那么我们就不需要为这两个ActivityRecord分别应用一段平移的动画,而是直接将这个平移的动画应用到它们共同的父容器Task上,并且实现的效果是一样的。这也就是”promote“的含义,动画的目标主体从ActivityRecord”提升“到了更高一级的Task上。

接着看代码,Transition.tryPromote。

2.1 Transition.tryPromote

在这里插入图片描述

主要逻辑为遍历Targets.mArray中的每一个ChangeInfo对象,调用Transition.canPromote方法来判断他们是否能够提升为父容器。

1)、如果不能,直接跳过该ChangeInfo对象,判断下一个。

2)、如果能,就说明提升成功。此外还要调用Transition.reportIfNotTop来继续判断它是否是organized(我的理解就是这个WindowContainer是否是系统开机后自动创建的,不是需要的时候再去创建的)。如果不是,那么将当前WindowContainer对应的ChangeInfo从局部变量targets中移除,然后把它的父WindowContainer对应的ChangeInfo加如到targets中。如果是,那么在不移除当前WindowContainer对应的ChangeInfo的前提下,把它的父WindowContainer对应的ChangeInfo加如到targets中。这里应该是针对organized的WindowContainer的特殊处理,确保organized的WindowContainer的变化也能够报告到WMShell那边。

因此重点其实是Transition.canPromote逻辑。

2.2 Transition.canPromote

在这里插入图片描述

感觉这段代码还是比较重要的,我们逐行分析。

2.2.1 片段1

在这里插入图片描述

1)、对应WindowContainer.canCreateRemoteAnimationTarget方法,目前只有TaskDisplayArea、TaskFragment以及ActivityRecord会返回true,其它类型的WindowContainer都会返回false,也就是说父容器不是这几类的WindowContainer将无法得到提升,那么目前只有这几种提升:WindowState到ActivityRecord,ActivityRecod到TaskFragment,TaskFragment到TaskFragment(因为TaskFragment存在嵌套,比如Home类型的TaskFragment),以及TaskFragment到TaskDisplayArea。另外从Transition.calculateTargets的逻辑我们看到了执行动画的target至少是WindowToken这一级的,并且看收集的逻辑,似乎也没有看到过直接收集WindowState的,因此实际上提升只存在以下几种情况:

  • ActivityRecod到TaskFragment。
  • TaskFragment到TaskFragment。
  • TaskFragment到TaskDisplayArea。

2)、如果找不到父WindowContainer对应的ChangeInfo,则不提升,返回false。

3)、如果父WindowContainer有ChangeInfo,但是此时的状态和收集开始时的状态没有变化,则不提升,返回false。

2.2.2 片段2

在这里插入图片描述

1)、如果当前要提升的WindowContainer是Wallpaper类型的,则不提升,返回false。

2)、如果当前WindowContainer前后的父WindowContainer不一致,即发生reparent了,则不提升,返回false。

2.2.3 片段3

在这里插入图片描述

遍历父WindowContainer的所有子WindowContainer:

1)、如果姊妹WindowContainer在Transition.mChanges中找不到一个对应的ChangeInfo对象,或者有这么一个ChangeInfo对象,但是该ChangeInfo对象不在Targets.mArray中,这种情况一共可以理解为这个姊妹WindowContainer没有参与到本次动画,那么还需要继续判断:

----1.1)、如果该姊妹WindowContainer可见,那么就不提升,直接返回false,当前WindowContainer无法提升到父WindowContainer。毕竟该姊妹WindowContainer是没有参与到动画中的,并且是可见的,如果你提升了,那后续动画执行的时候用户不是会看到该姊妹WindowContainer跟着一起动了嘛,这肯定是不对的。

----1.2)、如果该姊妹WindowContainer不可见,那么就跳过对这个WindowContainer的检查。不可见的姊妹WindowContainer对于本次动画也没有太大影响,即使跟着一起进行动画用户也看不到,直接跳过检查下一个姊妹WindowContainer就好了。

2)、如果姊妹WindowContainer从Transition.mChanges中能找到一个对应的ChangeInfo对象,并且该ChangeInfo对象也在局部变量targets中,那么认为该姊妹WindowContainer也参与了本次动画,那么分别为他们的TransitionMode调用Transition.reduceMode方法来看它们动画的大方向是否是一致的,首先是根据ChangeInfo.getTransitMode拿到各自的TransitionMode:

在这里插入图片描述

TransitionMode定义在TransitionInfo中:

在这里插入图片描述

看到Transition模式其实就是定义在WindowManager中的Transition类型的子集。

ChangeInfo.getTransitMode的内容也比较简单:

TRANSIT_CHANGE:收集阶段的可见性和Transition就绪阶段的可见性没有发生变化。

TRANSIT_OPEN:存在发生了变化,且当前可见,即从无到有。

TRANSIT_CLOSE:存在发生了变化,且当前不可见,即从有到无。

TRANSIT_TO_FRONT:存在没有发生变化,且当前可见,说明从后台移动到了前台,从不可见变为了可见。

TRANSIT_TO_BACK:存在没有发生变化,且当前不可见,说明从前台移动到了后台,从可见变为了不可见。

再根据Transition.reduceMode的逻辑:

在这里插入图片描述

  • TRANSIT_TO_BACK和TRANSIT_CLOSE是一类的。
  • TRANSIT_TO_FRONT和TRANSIT_OPEN是一类的。
  • TRANSIT_CHANGE单独一类。

如果动画的大方向是一致的,那么即使TRANSIT_TO_BACK和TRANSIT_CLOSE的动画有点差别,但是为了大局考虑,各别同志也不是不能适当调整一下来实现集体上的一致。

如果动画的大方向都不一致,那么它们中的无论哪个肯定都是不能提升为它们的父容器的。比如TaskA想向左平移,TaskB想向右平移,那么如果擅自提升为父容器TaskDisplayArea,不管TaskDisplayArea向左还是向右平移肯定都不合适,这种矛盾就属于不可调和了,那父容器TaskDisplayArea就不用管了,也就是别提升了,让冲突的TaskA和TaskB自己玩去吧。

3)、最后总结一下检查姊妹WindowContainer的这段逻辑,其实就是检查所有的姊妹WindowContainer中,有没有和当前WindowContainer冲突的姊妹WindowContainer,至于是否冲突则看是否满足了以下条件之一:

  • 检查所有没有参与动画的姊妹WindowContainer,看能否找到一个可见的。
  • 检查所有参与了动画的姊妹WindowContainer,看能否找到一个动画的大方向和当前WindowContainer不一致。

只要找到了这么一个姊妹WindowContainer,我们就无法提升动画的主体。

3 构建TransitionInfo对象

在这里插入图片描述

这一节我感觉其实没有什么好说的,大概介绍一下TransitionInfo以及它的内部类Change。

在这里插入图片描述

1)、TransitionInfo,实现了Parcelable,结合注释,用来收集WMCore这边的Transition信息,用来同步给WMShell的TransitionPlayer。成员变量大概有这些:

在这里插入图片描述

2)、TransitionInfo.Change,同样实现了Parcelable,代表了WindowContainer在一个Transition期间的变化。看其成员变量,保存的信息还是挺多的,还有一个RunningTaskInfo的对象:

在这里插入图片描述

再结合Transition.calculateTransitionInfo方法,很明显就大概能弄懂这两个类的作用:

1)、TransitionInfo,对应一个Transition对象,用来收集WMShell感兴趣的Transition的信息,后续同步给WMShell。

2)、TransitionInfo.Change,对应一个Transition.ChangeInfo对象,用来收集WMShell感兴趣的Transition.ChangeInfo的信息,后续同步给WMShell。

顺便一提,google为啥不将Transition中ChangeInfo的命名为”Change“,将TransitionInfo中的Change命名为”ChangeInfo“呢,强迫症犯了。

4 Transition移动到PLAYING状态

在这里插入图片描述

其实在Transition.onTransactionReady方法的开头已经将Transition.mState状态置为STATE_PLAYING,这里又调用了一个TransitionController.moveToPlaying方法,看下是干啥的:

在这里插入图片描述

其实也非常简单:

1)、开始动画了,意味着当前Transition已经不能收集了,所以将TransitionController.mCollectingTransition置空。特别的,如果有其它Transition在排队,那么就继续将TransitionController.mCollectingTransition赋值为排队队列队首的那个Transition,我播我的动画,你收集你的WindowContainer,互不干扰。

2)、将当前Transition添加到TransitionController.mPlayingTransitions:

在这里插入图片描述

一个当前处于playing状态的Transition的队列,也就是说playing的Transition可以有多个。

5 切换到WMShell:onTransitionReady

在这里插入图片描述

在Transition.onTransactionReady方法的最后,调用了ITransitionPlayer.onTransitionReady方法将切换到了WMShell:

在这里插入图片描述

切换到WMShell意味着Transition就绪阶段已经结束,正式进入Transition的playing阶段,Transitions.TransitionPlayerImpl.onTransitionReady就是我们下一篇文章的起点。

最后稍微看一下调用ITransitionPlayer.onTransitionReady方法之前调用的Transition.buildFinishTransaction方法:

在这里插入图片描述

传入的Transaction对象为Transition.mFinishTransaction,如该方法的注释所说,这里对”finish transaction“的操作保证了动画结束后,所有的”reparent“操作或者是Layer的变化将会得到重置,特别是Layer的几何信息(位置、缩放、旋转这些)。如果你的Layer在动画结束的时候在Layer的这些信息上的确有变化,那就要注意不要让这个方法把你对Layer的操作重置了。

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

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

相关文章

Flink底层原理解析:案例解析(第37天)

系列文章目录 一、flink架构 二、Flink底层原理解析 三、Flink应用场景解析 四、fink入门案例解析 文章目录 系列文章目录前言一、flink架构1. 作业管理器(JobManager)2. 资源管理器(ResourceManager)3. 任务管理器(Ta…

JavaScript统计字符串中出现次数最多的字符

思路&#xff1a;使用charAt()方法可以通过for循环来依次遍历出字符串中的字符 将遍历出来的字符作为一个空对象的属性 如果该对象中该属性没有值则对其赋值为1 如果该对象中已经有值了则在原基础上加1 最后通过for in循环比较对象中个属性值大大小然后将其打印出来 <!DOCT…

liunx面试题目

如何看当前Linux系统有几颗物理CPU和每颗CPU的核数&#xff1f; 查看物理cup&#xff1a; cat /proc/cpuinfo|grep -c ‘physical id’ 查看每颗cup核数 cat /proc/cpuinfo|grep -c ‘processor’ 若希望自动实现软件包的更新&#xff0c;可以使用yum-cron并启动该服务 yum -y …

C++ std::lock_guard和 std::unique_lock

二者都是 C 标准库中用于管理互斥锁&#xff08;mutex&#xff09;的 RAII&#xff08;Resource Acquisition Is Initialization&#xff09;机制的类。这些类可以确保互斥锁在构造时被获取&#xff0c;在析构时被释放&#xff0c;从而避免死锁和资源泄漏问题。不过&#xff0c…

Python基础语法篇(上)

Python基础语法&#xff08;上&#xff09; 一、基知二、基本数据类型&#xff08;一&#xff09;标准数据类型&#xff08;二&#xff09;数据类型转换 三、字符串基本操作&#xff08;一&#xff09;字符串的索引和切片&#xff08;二&#xff09;字符串的拼接 三、运算符四、…

web安全之跨站脚本攻击xss

定义: 后果 比如黑客可以通过恶意代码,拿到用户的cookie就可以去登陆了 分类 存储型 攻击者把恶意脚本存储在目标网站的数据库中(没有过滤直接保存)&#xff0c;当用户访问这个页面时&#xff0c;恶意脚本会从数据库中被读取并在用户浏览器中执行。比如在那些允许用户评论的…

Ansys Zemax|探索OS中的物理光学传播

概述 物理光学传播 (Physical Optics Propagation, POP) 分析是OpticStudio序列模式中的一个强大的分析工具&#xff0c;它可以用来分析光束的传播和光纤耦合的效率。这篇文章旨在介绍这一分析工具的功能&#xff0c;并向您展示一些具体的应用示例。本文同时为您介绍了如何使用…

有关电力电子技术的一些相关仿真和分析:⑦三相桥式电压型PWM逆变器与直接/间接法控制单相全桥结构PWM整流器(MATLAB/Siumlink仿真)

1.1 题目一要求 以三相桥式电压型PWM逆变器为对象,研究其在不同调制度下,输出电压的频谱成分变化,依据仿真波形分析其工作时序。 参数要求:三相桥式逆变电路,直流侧电压800V,调制波频率50HZ,开关频率10kHZ,阻感负载R=10Ω,L=5mH。 1.2 题目二要求 以单相全桥结构P…

高效接入电商订单API,掌握这些技巧轻松实现

受全渠道大趋势的影响&#xff0c;很多实体商家纷纷开展电商业务&#xff0c;为了提升业务管理效率&#xff0c;想要在原有管理系统的基础上通过接入电商订单API接口&#xff0c;方便将线上线下的订单进行统一管理&#xff0c;但各个电商平台的电商订单API接口那么多&#xff0…

allure_pytest:AttributeError: ‘str‘ object has no attribute ‘iter_parents‘

踩坑记录 问题描述&#xff1a; 接口自动化测试时出现报错&#xff0c;报错文件是allure_pytest库 问题分析&#xff1a; 自动化测试框架是比较成熟的代码&#xff0c;报错也不是自己写的文件&#xff0c;而是第三方库&#xff0c;首先推测是allure_pytest和某些库有版本不兼…

彩电上自带的推箱子游戏是什么编程语言开发的?

2000年左右的厦新彩电上&#xff0c;自带了推箱子、华容道游戏。界面如下&#xff1a; 在线版推箱子游戏&#xff0c;网址&#xff1a;https://www.tuixiangzi.cn/ BASIC&#xff0c;全称是Beginners All-purpose Symbolic Instruction Code&#xff0c;含义是初学者通用符号…

【IEEE出版顺利申请中】2024年第四届电子信息工程与计算机科学国际会议(EIECS 2024)

2024年第四届电子信息工程与计算机科学国际会议(EIECS 2024) 2024 4th International Conference on Electronic Information Engineering and Computer Science 中国延吉 | 2024年9月27-29日 电子信息的出现与计算机技术、通信技术和高密度存储技术的迅速发展并在各个领域里…

每日练习,不要放弃

目录 题目1.下面叙述错误的是 ( )2.java如何返回request范围内存在的对象&#xff1f;3.以下代码将打印出4.下列类定义中哪些是合法的抽象类的定义&#xff1f;&#xff08;&#xff09;5.以下代码段执行后的输出结果为6.以下代码运行输出的是总结 题目 选自牛客网 1.下面叙述…

深度学习驱动智能超材料设计与应用

在深度学习与超材料融合的背景下&#xff0c;不仅提高了设计的效率和质量&#xff0c;还为实现定制化和精准化的治疗提供了可能&#xff0c;展现了在材料科学领域的巨大潜力。深度学习可以帮助实现超材料结构参数的优化、电磁响应的预测、拓扑结构的自动设计、相位的预测及结构…

分析示例 | Simufact Additive铺粉增材制造工艺缺陷仿真分析方案

近年来&#xff0c;随着增材制造工艺的快速发展&#xff0c;仿真模拟的重要性日益凸显&#xff0c;越来越多的科研及应用单位选择在实际打印之前&#xff0c;通过仿真预测打印问题&#xff0c;从而优化打印工艺、减少物理试错次数、降低打印成本。就不同增材工艺仿真的占比而言…

netxduo http server 创建回复以及json解析

我们今天要整http的response,比如我创建的http server,我对它发送了一个POST,然后服务器解析出json里的body,再回复过去。今天会用到json的解析库cjson以及postman去发送消息。这次用nx_web_http_server.h这个库,不用之前的nx_http_server.h 本教程在最后附带app_netxduo…

大数据基础:Doris重点架构原理

文章目录 Doris重点架构原理 一、Apache Doris介绍 二、Apache Doris使用场景 三、Apache Doris架构原理 四、Apache Doris 特点 Doris重点架构原理 一、Apache Doris介绍 基于 MPP 架构的高性能、实时的分析型数据库&#xff0c;以极速易用的特点被人们所熟知&#xff…

JVM---对象是否存活及被引用的状态

1.如何判断对象是否存活 1.1 引用计数算法 概念&#xff1a;在对象头部增加一个引用计数器,每当有一个地方引用它时&#xff0c;计数器值就加一&#xff1b;当引用失效时&#xff0c;计数器值就减一&#xff1b;任何时刻计数器为零的对象就是不可能再被使用的。 优点&#xff1…

vue2迁移到vue3注意点

vue2迁移到vue3注意点 1、插槽的修改 使用 #default &#xff0c; 以及加上template 模板 2、 类型的定义&#xff0c;以及路由&#xff0c;vue相关资源&#xff08;ref, reactive,watch&#xff09;的引入等 3、类装饰器 1&#xff09;vue-class-component是vue官方库,作…

ubuntu搭建harbor私仓

1、环境准备 链接: https://pan.baidu.com/s/1q4XBWPd8WdyEn4l253mpUw 提取码: 7ekx --来自百度网盘超级会员v2的分享 准备一台Ubuntu 机器:192.168.124.165 将上面两个文件考入Ubuntu上面 2、安装harbor 安装Docker Harbor仓库以容器方式运行,需要先安装好docker,参考:…