Android的视图显示和管理机制:layout view window WindowManager Canvas Surface

在Android系统中,Layout view window WindowManager Canvas Surface SurfaceFlinger这些组件协同工作,以实现图形的绘制和显示。需要搞明白这些组件是什么时候创建的以及他们之间的结构关系。

  • 从上到下的层级关系:用户在View上进行操作,View通过Canvas进行绘制,绘制结果存储在Surface中。每个Window都可以关联一个或多个Surface。
  • 合成和显示:SurfaceFlinger获取所有活跃的Surface,并将它们合成为最终的屏幕显示内容。
  • 性能和异步处理:SurfaceView允许在后台线程中通过其Surface进行绘制,与主UI线程分离,这有助于处理复杂或资源密集型的图形操作,而不阻塞用户界面。

1 LayoutInflater

创建和获取

inflate方法用于将XML布局文件转换为应用程序中的View对象。这个过程是通过LayoutInflater类实现的,它是Android SDK的一部分,专门负责解析XML布局文件,并将其实例化为应用程序界面的层次结构。

setContentView最后会调用mLayoutInflater.inflate来创建了自定义xml中的布局视图,添加到mContentParent中。inflate方法是讲xml文件反射成一个View,但是并不执行View的绘制。

LayoutInflater是一个用于将定义在XML中的布局文件(如activity_main.xml)转化为View对象的类。每个由XML文件定义的布局在运行时都需要被“充气”成一个View树,这样用户才能与之交互。基本功能是读取XML布局文件,并将其转换成为相应的View对象。这个方法通常在Activity、Fragment或视图组件初始化时调用,以生成用户界面。

LayoutInflater提供了几个版本的inflate方法,其中最常用的包括:
View inflate(int resource, ViewGroup root)
View inflate(int resource, ViewGroup root, boolean attachToRoot)

  • resource:这是一个指向布局文件的资源ID,例如R.layout.my_layout。
  • root:这是新View应该附加到的父View。这个参数可以是null。
  • attachToRoot:如果是true,则将加载的View添加到root作为子项;如果是false,则不添加,但仍然会使用root来正确处理布局参数。

inflate过程详解

  1. 解析XML

    • LayoutInflater读取指定的XML布局文件,解析其中定义的各种UI组件(如Button、TextView等)和它们的属性(如android:layout_width)。
  2. 创建View对象

    • 对于XML中的每一个组件,LayoutInflater会创建对应的View对象。例如,一个标签会被实例化为一个Button对象。
  3. 处理属性

    • 每个View对象会根据XML中定义的属性进行配置。这些属性包括尺寸、边距、对齐方式等。
  4. 构建视图树

    • 如果inflate调用中提供了root且attachToRoot为true,解析出的View会被添加到root中,形成一个完整的视图树。如果attachToRoot为false,则不添加,但root仍然用于生成正确的布局参数。

inflate使用场景

  • 在Activity中:通常在onCreate()方法中使用inflate来加载布局。

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    }

  • 在Fragment中:在onCreateView()方法中使用inflate来为Fragment加载视图。
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_example, container, false);
    }

通常我们使用inflate有以下三种方式:

LayoutInflater inflater = LayoutInflater.from(this);
View view1 = inflater.inflate(R.layout.view1, null);
View view2 = inflater.inflate(R.layout.view2, null, false);

View.inflate:只有一种形式如下:其实质是通过LayoutInflater来创建View的
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}

Context.getSystemService:通过Context.getSystemService来获得LayoutInflater,实质也是通过LayoutInflater来创建View
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view1 = inflater.inflate(R.layout.view1, null);

2 View

创建和获取

创建: View 是 Android 中的基础绘图单元,通常在 XML 布局文件中定义或通过代码直接创建。每个 View 在被创建时会初始化其绘图属性(如大小、颜色等)。
获取: 通常,View 通过其父容器(如 Activity 或 Fragment 的布局)进行管理和访问。
View是Android中UI组件的基础,如按钮、文本框等。负责自己的绘制(通过onDraw方法)和事件处理。View组成ViewGroup(如LinearLayout)进而构建复杂的用户界面。

View机制

  • 自定义绘制的基础: Android中的所有可视化组件(如按钮(Button)、文本框(TextView)、输入框(EditText)等)都是基于View类或其子类构建的。View是UI组件的基类,它封装了与用户交互、布局管理和绘制的基本功能。

  • Canvas绘图上下文: 每个需要在屏幕上展示的View,在其生命周期中的某个时刻,都会获得一个Canvas对象。这个Canvas就像是一个画布,提供了丰富的绘图方法,如画线、画圆、填充颜色、绘制文本等。通过Canvas,每个View能够实现自定义的图形绘制逻辑,从而展现出独特的视觉效果和交互行为。

  • 绘制流程: 当UI需要更新或初次展示时,系统会要求相关的View执行其draw()方法。在draw()方法内部,View会使用分配给它的Canvas来执行绘制操作。这个过程包括但不限于背景绘制、内容绘制(比如文本或图像)以及绘制子视图(如果有的话)。通过重写onDraw()方法,开发者可以完全控制View的绘制逻辑,实现自定义的UI组件。

自定义View的意义

  • 个性化UI设计: 开发者可以创造出与系统默认组件外观迥异的UI元素,满足特定应用的设计需求或品牌风格。
  • 动态效果实现: 利用自定义绘制,可以轻松实现复杂的动画效果、图形变换等,增强用户体验。
  • 高效性能控制: 在一些高性能要求的场景(如游戏、复杂动画)中,直接操作Canvas进行绘制能更精细地控制渲染流程,提高应用性能。

3 Window

创建和获取

创建: 在 Android 中,Window 是一个抽象概念,代表屏幕上的一部分区域,可以承载视图内容。每个 Activity 自动关联一个 Window,通常是通过 PhoneWindow 实现的。
获取: 可以通过 Activity 的 getWindow() 方法获取到当前活动的 Window。

机制

Android手机中所有的视图都是通过Window来呈现的,像常用的Activity,Dialog,PopupWindow,Toast,他们的视图都是附加在Window上的。Window是一个更高级的UI概念,代表Android中的一个全屏窗口,比如一个活动(Activity)。它不直接参与内容的绘制,而是为放置视图提供一个容器或框架。

在这里插入图片描述

每一个Activity都包含一个Window对象(dialog,toast 等也是新添加的window对象),而Window是一个抽象类,具体实现是PhoneWindow。在Activity中的setContentView实际上是调用PhoneWindow的setContentView方法。并且PhoneWindow中包含着成员变量DecorView。

在Android中,Window不是一个具体的类,而是通过WindowManager服务管理的一个概念性框架。它代表了一个可以包含视图和布局的容器,这个容器可以完整地填充设备的屏幕或者只是屏幕的一部分(如对话框)。Window作为最顶层的UI容器,主要负责承载应用的视图层次结构。每个Android应用至少有一个Window(通常是主Activity的窗口),复杂应用可能有多个Window(如弹出的对话框,菜单等)。

每个Activity通常都会有一个与之关联的Window,这个Window负责展示Activity的内容。当你创建一个Activity时,系统会为其提供一个Window,这个Window实际上是由Activity的setContentView()方法填充的。

在这里插入图片描述

站在系统的角度上看,系统是不知道有View对象这个说法的!作为系统,不去管你Window如何搬砖、如何砌墙,只给你地皮。而这时,Window为了绘制出用户想要的组件(按钮、文字、输入框等等),于是就定义了View机制,给每个View提供Canvas,让不同的View自己绘制具有自己特色的组件。同时,为了更好的管理View,通过定义ViewGroup等等

在Activity的attach()方法里,系统会创建Activity所属的Window对象并为其设置回调接口,由于Activity实现了Window的Callback接口,因此当Window接收到外界的状态改变时就会回调Activity的方法。Callback接口中的方法很多。Activity实现了Window的Callback接口,因此当Window接收到外界的状态改变时就会回调Activity的方法

public interface Callback {public boolean dispatchTouchEvent(MotionEvent event);public View onCreatePanelView(int featureId);public boolean onMenuItemSelected(int featureId, MenuItem item);public void onContentChanged();public void onWindowFocusChanged(boolean hasFocus);public void onAttachedToWindow();public void onDetachedFromWindow();}

4 WindowManager

创建和获取

创建: WindowManager 是一个系统服务,负责管理应用窗口的创建、销毁、更新等。它是在系统启动时由 SystemService 创建的。
获取: WindowManager 可以通过 Context.getSystemService(Context.WINDOW_SERVICE) 获得。

机制

WindowManager是Android系统中管理窗口的服务,负责管理所有的Window,包括它们的创建、销毁、大小调整和Z顺序(即窗口堆叠的顺序)。WindowManager通过WindowManager.LayoutParams类提供对窗口特性的详细控制,如其尺寸、透明度、位置等。在LayoutParams中,有2个比较重要的参数: flags,type。

PhoneWindow 只是负责处理一些应用窗口通用的逻辑(设置标题栏,导航栏等)。但是真正完成把一个 View,作为窗口添加到 WmS 的过程是由 WindowManager 来完成的。WindowManager 的具体实现是 WindowManagerImpl。这个WindowManagerImpl都是交由WindowManagerGlobal来处理,WindowManagerGlobal以工厂的形式向外提供自己的实例。这种工作模式是桥接模式,将所有的操作全部委托给WindowManagerGlobal来实现。

添加窗口是通过WindowManagerGlobal的addView方法操作的,这里有三个必要参数。view,params,display。
display : 表示要输出的显示设备。
view : 表示要显示的View,一般是对该view的上下文进行操作。(view.getContext())
params : 类型为WindowManager.LayoutParams,即表示该View要展示在窗口上的布局参数。其中有一个重要的参数type,用来表示窗口的类型。

在WindowManagerGlobal的addView()方法里,最后调用ViewRootImpl的setView方法,处理添加过程。

在这里插入图片描述

在ViewRootImpl的setView()方法里,执行requestLayout()方法完成View的绘制流程,并且通过WindowSession将View和InputChannel添加到WmS中,从而将View添加到Window上并且接收触摸事件。
当手动调用 invalidate(),postInvalidate(),requestInvalidate() 也会最终调用performTraversals(),来重新绘制 View。
在setView方法中,首先会调用到 requestLayout(),表示添加 Window 之前先完成第一次 layout 布局过程,以确保在收到任何系统事件后面重新布局。ViewRootImpl 调用到 requestLayout() 来完成 View 的绘制操作,view 的绘制首先会调用 checkThread() 来判断当前线程。通过requestLayout()向主线程发送了一条触发遍历操作的消息,performTraversals方法开始遍历整个View树,执行View的measure,layout,draw流程。ViewRootImpl中接收的各种变化,如来自WmS的窗口属性变化、来自控件树的尺寸变化及重绘请求等都引发performTraversals()的调用,并在其中完成处理。View类及其子类中的onMeasure()、onLayout()、onDraw()等回调也都是在performTraversals()的执行过程中直接或间接的引发。
在这里插入图片描述

performMeasure : 会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有的子元素进行measure过程,这个时候measure流程就从父容器传到子元素中了,这样就完成了一次measure过程。measure完成以后,可以通过getMeasuredWidth和getMeasureHeight方法来获取到View测量后的宽高。

performLayout : 和performMeasure同理。Layout过程决定了View的四个顶点的坐标和实际View的宽高,完成以后,可以通过getTop/Bottom/Left/Right拿到View的四个顶点位置,并可以通过getWidth和getHeight方法来拿到View的最终宽高。

performDraw : 和performMeasure同理,唯一不同的是,performDraw的传递过程是在draw方法中通过dispatchDraw来实现的。Draw过程则决定了View的显示,只有draw方法完成以后View的内容才能呈现在屏幕上。

在这里插入图片描述

它只提供三个接口方法:addView、updateViewLayout、removeView,这些方法都是针对View的。
在这里插入图片描述

5 Surface

创建和获取

当一个应用程序窗口被创建时,系统会为该窗口创建一个Surface。这个Surface是由窗口管理器(Window Manager)和表面合成器(SurfaceFlinger)共同管理的。
在应用程序的ViewRootImpl类中,有一个名为mAttachInfo的内部类,它持有当前窗口的Surface引用。这个引用是在窗口创建时由系统设置的,并在窗口的生命周期中保持有效。

Surface 表示一个具体的可绘制区域,通常是由 SurfaceView 或者窗口系统(如 Window)来创建和管理。Surface 与底层的图形缓冲区关联,用于存储实际的像素数据。
可以通过 SurfaceView.getHolder().getSurface() 获得,或者从 Window 的某些方法中间接获取。

Surface 的作用:

在draw阶段,每个视图通过调用其draw方法将自身绘制到一个Canvas对象上。这个Canvas实际上是通过Surface的lockCanvas方法获取的,它代表了Surface的一块画布。
视图的绘制操作(如画线、画圆、贴图等)都是在这个Canvas上执行的。完成绘制后,通过Surface的unlockCanvasAndPost方法将结果显示到屏幕上。

表示一个具体的绘图表面,这个表面可以存储绘制好的图像数据。在更底层,与一个被称为SurfaceHolder的缓冲区相关联,这使得SurfaceView一个特殊的View可以在一个独立的线程中更新其内容,而不影响主UI线程的性能。

在Android中,Window与Surface一一对应。 如果说Window关心的是层次和布局,是从设计者角度定义的类,Surface则从实现角度出发,是工程师关心和考虑的类。Window的内容是变化 的,Surface需要有空间来记录每个时刻Window的内容。在Android的SurfaceFlinger实现里,通常一个Surface有两块 Buffer, 一块用于绘画,一块用于显示,两个Buffer按照固定的频率进行交换,从而实现Window的动态刷新。

每个Window在Android中都关联着一个Surface,这个Surface是应用程序用来绘制其用户界面(UI)的地方。当应用程序需要更新其显示内容时,它会在对应的Surface上绘制新的UI元素,如按钮、文本或者图像。这一过程可以发生在主线程中,也可以在专门的渲染线程中,特别是对于需要复杂动画或视频播放的场景。

Surface的工作流程通常包括以下几个关键步骤:

  1. 创建:Surface在窗口创建时被创建,为应用程序提供一块可供绘制的“空画布”。

  2. 锁定和绘制:应用通过锁定Surface,获得一个Canvas对象,然后在这个Canvas上进行绘制操作。

  3. 提交:绘制完成后,Surface会被解锁并提交,这意味着绘制的内容已经准备好用于显示。

  4. 合成与显示:SurfaceFlinger系统服务负责从不同的Surface中读取已提交的缓冲区数据,进行合成(如果存在多个叠加的窗口),然后输出到显示屏上。

SurfaceView是一种特殊的View,它有自己的Surface,允许在单独的线程中进行高效的后台绘制,这对于视频播放或游戏等高性能图形应用特别有利,因为它减少了主线程的负担,并且支持在不阻塞UI更新的情况下进行快速连续的图像更新。

6 Canvas

创建和获取

Canvas是一个提供绘图功能的类,它定义了绘制文本、线条、图形、图片等的方法。在View的onDraw方法中,Canvas对象被传递进来,开发者通过这个Canvas来绘制自定义的UI内容。

performTraversals方法中ViewRootImpl就会去创建Surface,而此后的渲染则可以通过Surface的lockCanvas方法获取Surface的Canvas来进行,然后遍历ViewHierachy把需要绘制的View通过Canvas(View.onDraw(Canvas canvas))绘制到Surface上,绘制完成后解锁(Surface.unlockCanvasAndPost)让SurfaceFlinger将Surface绘制到屏幕上。我们onDraw(Canvas canvas)方法中传入的Canvas对象大致就是这么来的……Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都是画在Surface上的,传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行.但是viewgroup在依次绘制子view的时候,都会先对canvas进行save操作,绘制完之后restore,所以其实虽然绘制都共用同一个canvas,但是子view之间的绘制是互不影响的

机制

一个Canvas对象有四大基本要素:
1、一个用来保存像素的Bitmap
2、一个Canvas在Bitmap上进行绘制操作
3、绘制的东西
4、绘制的画笔Paint

Canvas类提供了一系列的draw…方法
填充 public void drawARGB(int a, int r, int g, int b)
绘制几何图像 canvas.drawArc (扇形)
绘制图片 canvas.drawBitmap (位图)

7 SurfaceFlinger

创建和获取

创建: SurfaceFlinger 是系统级的服务,由系统在启动时初始化。它负责管理所有应用和系统的 Surface,并进行屏幕内容的合成。
获取: 作为系统服务,开发者通常不直接与 SurfaceFlinger 交互;它在后台运行,通过系统调用间接与之交互。

机制

SurfaceFlinger是系统级别的服务,用于管理所有的Surface。它负责将来自不同应用和系统界面的多个Surface合成到一个帧缓冲区中,并输出到设备的显示屏上。通过硬件加速和优化算法来有效地进行这种图像合成,以实现高性能的图形显示。

在这里插入图片描述

SurfaceFlinger是一个独立的Service,它接收所有Window的Surface作为输入,根据ZOrder, 透明度,大小,位置等参数,计算出每个Surface在最终合成图像中的位置,然后交由HWComposer或OpenGL生成最终的显示Buffer, 然后显示到特定的显示设备上。

Layer——Layer是SurfaceFlinger 进行合成的基本操作单元。Layer在应用请求创建Surface的时候在SurfaceFlinger内部创建,因此一个Surface对应一个 Layer, 但注意,Surface不一定对应于Window,Android中有些Surface并不跟某个Window相关,而是有程序直接创建,比如说 SurfaceView, 用于显示有硬件输出的视频内容等。当多个Layer进行合成的时候,并不是整个Layer的空间都会被完全显示,根据这个Layer最终的显示效果,一个Layer可以被划分成很多的Region

在这里插入图片描述

应用程序的每个Surface都对应一个SurfaceFlinger端的Layer,每个Layer都有两个buffer可以用,一个前端buffer,一个后端buffer,前端buffer用于显示,后端buffer用于绘制,SurfaceFlinger所要做的事情就是把后端buffer绘制完成后需要显示的buffer进行合成,合成到framebuffer上,然后丢给Display去显示。

双缓冲的主要目的是减少画面撕裂和避免渲染过程中的视觉闪烁。通过在后台缓冲区进行绘制,然后一次性将完成的画面切换到前台,可以提供更平滑和更稳定的视觉效果。

  • 当SurfaceFlinger作为消费者时,它会取用Surface的frontBuffer中的图像,将其与系统中其他的Surface图像合成,然后输出到屏幕。
  • 当MediaCodec作为消费者时,frontBuffer中的内容被用于视频编码过程,编码后的数据通常用于存储或网络传输。

工作流程

  • Lock:通过lockCanvas()方法获取对backBuffer的访问,这允许在后台缓冲区上进行绘制。这个过程中,应用程序可以在这个画布上绘制图像、文本、动画等内容。
  • Draw:在backBuffer上完成所有绘制操作。由于这些操作是在后台执行的,它们不会影响当前用户看到的屏幕内容。
  • Unlock and Post:完成绘制后,调用unlockCanvasAndPost(Canvas canvas),这个操作不仅释放画布资源,同时触发缓冲区的交换。此时,backBuffer(新绘制的内容)和frontBuffer(当前显示的内容)的身份互换,新的内容变为可显示的,而旧的前台缓冲区则转为后台,准备下一轮绘制。

Surface 和 SurfaceFlinger 的基本关系

  1. Surface: 在Android中,Surface代表一块可显示内容的区域。它是一个虚拟的显示层,可以接收绘制命令(通过Canvas),并保存绘制的内容。

  2. SurfaceFlinger: SurfaceFlinger是Android系统的底层服务,负责接收各个应用和系统服务的图像数据(即Surface数据),并将这些数据合成到屏幕上。SurfaceFlinger工作在系统级别,管理着所有的Surface,并负责最终的屏幕渲染。

Surface 到 SurfaceFlinger 的数据流动

  • 应用程序通过Canvas对象在Surface上进行绘制。这些操作实质上是在修改与Surface关联的硬件缓冲区的内容。

  • 绘制完成后,通过Surface的方法(如unlockCanvasAndPost(Canvas canvas))将修改后的缓冲区标记为待显

  • Surface内部实现了与SurfaceFlinger的通信机制。每个Surface都是通过Binder IPC机制注册到SurfaceFlinger服务的。

  • Surface内容更新时,Surface会通知SurfaceFlinger其内容已更新。这通常通过发送一个同步信号(例如,一个时间戳或帧标识)来实现。

  • SurfaceFlinger接收到更新通知后,会将新的Surface内容拉取到其合成流程中。SurfaceFlinger根据所有可用的Surface图层和它们的Z顺序进行图像合成,然后输出到显示硬件。

  • SurfaceFlinger合成的结果会发送到显示硬件(如LCD屏幕)。这一步通常涉及到VSYNC信号,确保屏幕刷新与内容更新同步,从而减少图像撕裂或闪烁现象。

surfaceflinger的工作流程

在这里插入图片描述

当Surface绘制完成后会发出一个Invalidate的消息给Surfaceflinger的等待线程,当waitForEvent接收到消息后就会交给onMessageReceivered去处理,处理过程中会依次调用handleMessageTransaction、handleMessageInvalidate、handleMessageRefresh接口。

handleMessageTransaction——主要处理之前对屏幕和应用程序窗口的改动。窗口状态的改变只能在一个Transaction中进行。因为窗口状态的改变可能造成本窗口和其他窗口的可见区域变化,所以就必须重新来计算窗口的可见区域。在这个处理子过程中Android会根据标志位来对所有layer进行遍历,一旦发现哪个窗口的状态发生了变化就设置标志位以在将来重新计算这个窗口的可见区域。

handleMessageInvalidate——主要调用handlePageFlip()函数,该函数主要是从各Layer对应的BufferQueue中拿图形缓冲区数据,并根据内容更新脏区域。

handleMessageRefresh——就是合并和渲染输出了。

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

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

相关文章

考研踩坑经验分享

文章目录 写在前面自身情况简介自身学习路线优点坑点 学习路线建议1、2和3月份3、4和5月份6、7和8月份9、10月份11、12月份 一些私货建议结尾 写在前面 考研是一件非常有盼头的事,但绝对不是一件容易的事。 如果你不能做好来年三月份出成绩时,坦然接受…

Ubuntu 下使用 Scons 交叉编译嘉楠堪智 CanMV K230 大小核 Coremark 程序

在 Ubuntu 下使用 SCons 进行交叉编译嘉楠堪智 CanMV K230 大小核(不同的玄铁 C908 核心)的 C 程序,以 Coremark 程序为例,顺便测试一下大小核和编译器的性能。 2024年3月14日,嘉楠科技宣布推出了全球首款支持 RISC-V…

# 从浅入深 学习 SpringCloud 微服务架构(十七)--Spring Cloud config(1)

从浅入深 学习 SpringCloud 微服务架构(十七)–Spring Cloud config(1) 一、配置中心的 概述 1、配置中心概述 对于传统的单体应用而言,常使用配置文件来管理所有配置,比如 SpringBoot 的 application.y…

消费金融平台公司如何做大做强自营产品

本文来自于2019年的某次内部分享沟通会,部分敏感内容已做删减。

油泼辣子在食品类别可以申请成商标不!

前阵韩国人在美国申请“chili crunch”油泼辣子作为商标,还准备禁止华人餐馆使用投诉侵权并索赔,普推知产老杨在USPTO上面检索发现,这个人申请的主要是30类方便食品的调味品,商标分类是全球通用的。 商标名称不能申请本类所属的通…

C/C++常用的内置的宏定义

常用的C/C 内置宏 这是我在VS2015下运行的 cout << "file " << __FILE__ << endl;cout << "line " << __LINE__ << endl;cout << "date " << __DATE__ << endl;cout << "…

力扣HOT100 - 55. 跳跃游戏

解题思路&#xff1a; class Solution {public boolean canJump(int[] nums) {int n nums.length;int maxReach 0;// 正常来说每次至少跳一格&#xff0c;所以最多循环n次for (int i 0; i < n; i) {if (i > maxReach) return false;// 这种情况代表遇到了0&#xff0…

机器学习周报第三十八周 iTransformer

文章目录 week38 iTransformer摘要Abstract一、文献阅读1. 题目2. abstract3. 网络架构**转置Embedding&#xff1a;****LayerNorm&#xff08;层归一化&#xff09;****Feed-forward network&#xff08;前馈网络&#xff09;****Multivariate-Attention&#xff08;多变量注意…

大数据比赛-环境搭建(一)

1、安装VMware Workstation 链接&#xff1a;https://pan.baidu.com/s/1IvSFzpnQFl3svWyCGRtEmg 提取码&#xff1a;ukpo 内有安装包及破解方式&#xff0c;安装教程。 2、下载Ubuntu系统 阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 (aliyun.com) 点击下载&#xff…

四川汇昌联信:拼多多运营属于什么行业?

拼多多运营属于什么行业?这个问题看似简单&#xff0c;实则涉及到了电商行业的深层次理解。拼多多运营&#xff0c;顾名思义&#xff0c;就是在拼多多这个电商平台上进行商品销售、推广、客户服务等一系列活动。那么&#xff0c;这个行业具体包含哪些内容呢?下面就从四个不同…

Verilog复习(四)| 组合逻辑

一位全加器结构描述&#xff1a; 数据流描述&#xff1a; 行为描述&#xff1a; 只要有事件发生&#xff08;列表中任何 信号有变化&#xff09;&#xff0c;就执行begin…end 的语句 。 always的事件控制方式 边沿触发 always (posedge clk) // clk从低电平->高&#x…

QT自适应界面 处理高DPI 缩放比界面乱问题

1.pro文件添加 必须添加要不找不到 QT版本需要 5。4 以上才支持 QT widgets 2.main界面提前处理 // 1. 全局缩放使能QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);// 2. 适配非整数倍缩放QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::High…

打印图形(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i, j;//循环打印&#xff1b;for (i 0; i < 5; i){//列&#xff1b;for (j 0; j &…

SpringBoot+Vue实现图片滑块和文字点击验证码

一、背景 1.1 概述 传统字符型验证码展示-填写字符-比对答案的流程&#xff0c;目前已可被机器暴力破解&#xff0c;应用程序容易被自动化脚本和机器人攻击。 摒弃传统字符型验证码&#xff0c;采用行为验证码采用嵌入式集成方式&#xff0c;接入方便&#xff0c;安全&#…

光伏电站智能管理平台功能全面介绍

一、介绍 光伏电站智能管理平台专门为了光伏电站服务的融合了项目沟通、在线设计、施工管理、运维工单等多智能光伏管理系统&#xff0c;可以满足光伏电站建设前期沟通、中期建设和后续维护的一体化智能平台&#xff0c;同时通过组织架构对企业员工进行线上管理和数据同步&…

BUU-二维码

题目 解题 打开是一张图片&#xff0c;扫描二维码后显示 secret is here 一时没有思路&#xff0c;看别人的wp https://blog.csdn.net/wusimin432503/article/details/125692459https://blog.csdn.net/weixin_45728231/article/details/120988424?spm1001.2101.3001.6661.1…

显卡、显卡驱动、CUDA、cuDNN、CUDA Toolkit、NVCC、nvidia-smi等概念的区别与联系

在科技日新月异的今天&#xff0c;显卡、显卡驱动、CUDA、cuDNN、CUDA Toolkit、NVCC、nvidia-smi等术语已经成为了科技领域的重要组成部分。本文旨在阐述这些术语之间的区别与联系&#xff0c;帮助您更好地理解它们在技术生态系统中的作用。 一、显卡 显卡&#xff0c;也称为…

(动画详解)LeetCode面试题 02.04.分割链表

&#x1f496;&#x1f496;&#x1f496;欢迎来到我的博客&#xff0c;我是anmory&#x1f496;&#x1f496;&#x1f496; 又和大家见面了 欢迎来到动画详解LeetCode系列 用通俗易懂的动画的动画使leetcode算法题可视化 先来自我推荐一波 个人网站欢迎访问以及捐款 推荐阅读…

[AutoSar]BSW_Diagnostic_003 ReadDataByIdentifier(0x22)介绍

目录 关键词平台说明背景一、请求格式二、常用DID三、响应格式四、NRC五、case 关键词 嵌入式、C语言、autosar、OS、BSW、UDS、diagnostic 平台说明 项目ValueOSautosar OSautosar厂商vector &#xff0c; EB芯片厂商TI 英飞凌编程语言C&#xff0c;C编译器HighTec (GCC)au…

Linux环境下parted工具使用

在工作中&#xff0c;我们经常会遇到大于分区大于2T的磁盘&#xff0c;由于系统盘最大不能超2T&#xff0c;我们会在做raid时将划分VD来进行装系统&#xff0c;但系统自动安装后无法将磁盘全部识别出来&#xff0c;管理员有时会要求手动对分区进行挂载&#xff0c;这个文档介绍…