Android 12系统源码_窗口管理(八)WindowConfiguration的作用

前言

在Android系统中WindowConfiguration这个类用于管理与窗口相关的设置,该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数,应用程序通过该类提供的信息可以更好的适配不同的屏幕布局和窗口环境,以提高用户体验。

一、类定义

frameworks/base/core/java/android/app/WindowConfiguration.java

public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {
	//包含装饰窗口在内的窗口显示区域
    private Rect mBounds = new Rect();
    //不包含装饰窗口在内的窗口显示区域
    private Rect mAppBounds;
    //可显示的最大区域
    private final Rect mMaxBounds = new Rect();
	//当前屏幕设备的旋转角度
    private int mRotation = ROTATION_UNDEFINED;
    //当前窗口模式
    private @WindowingMode int mWindowingMode;
    //屏幕窗口模式
    private @WindowingMode int mDisplayWindowingMode;
    /** @hide */
    @IntDef(prefix = { "WINDOWING_MODE_" }, value = {
            WINDOWING_MODE_UNDEFINED,//未定义
            WINDOWING_MODE_FULLSCREEN,//全屏
            WINDOWING_MODE_MULTI_WINDOW,//多窗口
            WINDOWING_MODE_PINNED,
            WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
            WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
            WINDOWING_MODE_FREEFORM,
    })
    public @interface WindowingMode {}
    //Activity的类型
    private @ActivityType int mActivityType;
    /** @hide */
    @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {
            ACTIVITY_TYPE_UNDEFINED,
            ACTIVITY_TYPE_STANDARD,
            ACTIVITY_TYPE_HOME,
            ACTIVITY_TYPE_RECENTS,
            ACTIVITY_TYPE_ASSISTANT,
            ACTIVITY_TYPE_DREAM,
    })
    public @interface ActivityType {}
	//窗口是否总是位于最上层
    private @AlwaysOnTop int mAlwaysOnTop;
        /** @hide */
    @IntDef(prefix = { "ALWAYS_ON_TOP_" }, value = {
            ALWAYS_ON_TOP_UNDEFINED,
            ALWAYS_ON_TOP_ON,
            ALWAYS_ON_TOP_OFF,
    })
    private @interface AlwaysOnTop {}
}

在这里插入图片描述
该类主要有以下几个关键属性:

  • mBounds: 屏幕尺寸
  • mAppBounds:不包含装饰窗口在内的窗口显示区域**(根据源码发现mAppBounds只排除了导航栏这个装饰窗口所在的区域,状态栏和输入法等装饰窗口所在的区域是被包含在内的)**
  • mMaxBounds:窗口可显示的最大区域
  • mRotation:当前屏幕设备的旋转角度
  • mWindowingMode:当前窗口的窗口模式,例如未定义、全屏、分屏、多窗口等
  • ActivityType:页面类型,例如未定义、标准、首页、最近任务等
  • mAlwaysOnTop:窗口是否总是位于最上层

二、WindowConfiguration的属性设置

2.1 Configuration类

WindowConfiguration在Android系统中基本都是作为Configuration类的内部属性出现的。

frameworks/base/core/java/android/content/res/Configuration.java

public final class Configuration implements Parcelable, Comparable<Configuration> {

    public final WindowConfiguration windowConfiguration = new WindowConfiguration();

 }

2.2 计算当前屏幕尺寸和当前窗口可显示的最大区域

这里我们主要是结合WMS模块的相关代码来分析WindowConfiguration的各个属性的来源;系统主要是通过DisplayContent的computeScreenConfiguration方法来计算当前屏幕对应的窗口配置信息的。

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
        implements WindowManagerPolicy.DisplayContentInfo {
        
    DisplayInfo computeScreenConfiguration(Configuration outConfig, int rotation) {
        final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);//屏幕旋转角度
        final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;//屏幕宽度
        final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;//屏幕高度
        //注释1,对屏幕的实际宽高进行存储
        outConfig.windowConfiguration.setMaxBounds(0, 0, dw, dh);
        outConfig.windowConfiguration.setBounds(outConfig.windowConfiguration.getMaxBounds());

        final int uiMode = getConfiguration().uiMode;//UI模式
        final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation).getDisplayCutout();//计算屏幕的显示切口
        //注释2,调用computeScreenAppConfiguration方法
        computeScreenAppConfiguration(outConfig, dw, dh, rotation, uiMode, displayCutout);
      	...代码省略...   
     }
     
 }

在注释1处根据屏幕旋转角度和基本显示尺寸,确定屏幕的实际宽高,并将其存储到WindowConfiguration的mMaxBounds属性和mBounds属性中。
在注释2处将屏幕实际宽度、高度、旋转角度、UI模式、屏幕显示切口作为参数,调用computeScreenAppConfiguration方法计算当前窗口可显示的安全区域。

2.3 计算当前窗口可显示的安全区域

class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
        implements WindowManagerPolicy.DisplayContentInfo {
   
    private final DisplayPolicy mDisplayPolicy;

    private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh,
            int rotation, int uiMode, DisplayCutout displayCutout) {
        //注释1,获取不包含系统装饰窗口的可显示屏幕区域
        final Point appSize = mDisplayPolicy.getNonDecorDisplaySize(dw, dh, rotation, uiMode, displayCutout);
        //注释2,获取不包含系统装饰窗口的可显示屏幕边界
        mDisplayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
        final int leftInset = mTmpRect.left;
        final int topInset = mTmpRect.top;
        //注释3,存储应用的可显示的安全区域
        outConfig.windowConfiguration.setAppBounds(leftInset /* left */, topInset /* top */,
                leftInset + appSize.x /* right */, topInset + appSize.y /* bottom */);
        //存储屏幕旋转角度
        outConfig.windowConfiguration.setRotation(rotation);
        //存储屏幕是横屏还是竖屏
        outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
        //屏幕像素密度
        final float density = mDisplayMetrics.density;
        final Point configSize = mDisplayPolicy.getConfigDisplaySize(dw, dh, rotation, uiMode,
                displayCutout);
        outConfig.screenWidthDp = (int) (configSize.x / density);
        outConfig.screenHeightDp = (int) (configSize.y / density);
        outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
        outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);

        final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
        outConfig.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, uiMode, dw,
                dh);
    }
    
 }

frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java

public class DisplayPolicy {

    Point getNonDecorDisplaySize(int fullWidth, int fullHeight, int rotation, int uiMode,
            DisplayCutout displayCutout) {
        int width = fullWidth;
        int height = fullHeight;
        int navBarReducedHeight = 0;
        int navBarReducedWidth = 0;
        //获取导航栏的位置
        final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
        if (hasNavigationBar()) {
            if (navBarPosition == NAV_BAR_BOTTOM) {
                navBarReducedHeight = getNavigationBarHeight(rotation, uiMode);
            } else if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
                navBarReducedWidth = getNavigationBarWidth(rotation, uiMode, navBarPosition);
            }
        }
        if (mExtraNavBarAlt != null) {
            final LayoutParams altBarParams = mExtraNavBarAlt.getLayoutingAttrs(rotation);
            final int altBarPosition = getAltBarPosition(altBarParams);
            if (altBarPosition == ALT_BAR_BOTTOM || altBarPosition == ALT_BAR_TOP) {
                if (altBarPosition == navBarPosition) {
                    navBarReducedHeight = Math.max(navBarReducedHeight,
                            getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));
                } else {
                    navBarReducedHeight += getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR);
                }
            } else if (altBarPosition == ALT_BAR_LEFT || altBarPosition == ALT_BAR_RIGHT) {
                if (altBarPosition == navBarPosition) {
                    navBarReducedWidth = Math.max(navBarReducedWidth,
                            getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));
                } else {
                    navBarReducedWidth += getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR);
                }
            }
        }
        //当前窗口的安全显示区域为屏幕宽高减去导航栏所在的区域
        height -= navBarReducedHeight;
        width -= navBarReducedWidth;
        //如果屏幕显示切口对象不为空,还要减去该区域
        if (displayCutout != null) {
            height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
            width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
        }
        return new Point(width, height);
    }
	
    public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
            DisplayCutout displayCutout, Rect outInsets) {
        outInsets.setEmpty();
        //系统存在导航栏
        if (hasNavigationBar()) {
            final int uiMode = mService.mPolicy.getUiMode();
            //获取导航栏的位置,最终返回的边界区域要去掉导航栏所在的区域
            int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
            if (position == NAV_BAR_BOTTOM) {
                outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
            } else if (position == NAV_BAR_RIGHT) {
                outInsets.right = getNavigationBarWidth(displayRotation, uiMode, position);
            } else if (position == NAV_BAR_LEFT) {
                outInsets.left = getNavigationBarWidth(displayRotation, uiMode, position);
            }
        }
        if (mExtraNavBarAlt != null) {
            final LayoutParams extraNavLayoutParams =
                    mExtraNavBarAlt.getLayoutingAttrs(displayRotation);
            final int position = getAltBarPosition(extraNavLayoutParams);
            if (position == ALT_BAR_BOTTOM) {
                outInsets.bottom = Math.max(outInsets.bottom,
                        getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));
            } else if (position == ALT_BAR_RIGHT) {
                outInsets.right = Math.max(outInsets.right,
                        getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));
            } else if (position == ALT_BAR_LEFT) {
                outInsets.left = Math.max(outInsets.left,
                        getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));
            } else if (position == ALT_BAR_TOP) {
                outInsets.top = Math.max(outInsets.top,
                        getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));
            }
        }
        //如果屏幕显示切口对象不为空,还要减去该区域
        if (displayCutout != null) {
            outInsets.left += displayCutout.getSafeInsetLeft();
            outInsets.top += displayCutout.getSafeInsetTop();
            outInsets.right += displayCutout.getSafeInsetRight();
            outInsets.bottom += displayCutout.getSafeInsetBottom();
        }
    }

 }

在注释1处调用DisplayPolicy的getNonDecorDisplaySize方法,获取不包含系统装饰窗口的可显示屏幕区域,将结果存放在类型为Point的appSize对象中,结合getNonDecorDisplaySize方法源码可以发现该方法只是去除了导航栏窗口所在的区域,另外如果有屏幕显示切口区域,还会去除屏幕显示切口区域。
在注释2处调用DisplayPolicy的getNonDecorInsetsLw方法,获取不包含系统装饰窗口的可显示屏幕边界,将结果存放在类型为Rect的mTmpRect对象中,结合getNonDecorInsetsLw方法源码可以发现该方法只是去除了导航栏窗口所在的区域,另外如果有屏幕显示切口区域,还会去除屏幕显示切口区域。
在注释3处会结合appSize和mTmpRect,将当前窗口可显示的安全区域存储到Configuration的WindowConfiguration中。

三、WindowConfiguration的作用

WindowConfiguration的toString方法包含了此类的所有关键信息。

public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {
   
    @Override
    public String toString() {
        return "{ mBounds=" + mBounds
                + " mAppBounds=" + mAppBounds
                + " mMaxBounds=" + mMaxBounds
                + " mWindowingMode=" + windowingModeToString(mWindowingMode)
                + " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode)
                + " mActivityType=" + activityTypeToString(mActivityType)
                + " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)
                + " mRotation=" + (mRotation == ROTATION_UNDEFINED
                        ? "undefined" : rotationToString(mRotation))
                + "}";
    }

    public static String windowingModeToString(@WindowingMode int windowingMode) {
        switch (windowingMode) {
            case WINDOWING_MODE_UNDEFINED: return "undefined";
            case WINDOWING_MODE_FULLSCREEN: return "fullscreen";
            case WINDOWING_MODE_MULTI_WINDOW: return "multi-window";
            case WINDOWING_MODE_PINNED: return "pinned";
            case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";
            case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";
            case WINDOWING_MODE_FREEFORM: return "freeform";
        }
        return String.valueOf(windowingMode);
    }
    
    public static String activityTypeToString(@ActivityType int applicationType) {
        switch (applicationType) {
            case ACTIVITY_TYPE_UNDEFINED: return "undefined";
            case ACTIVITY_TYPE_STANDARD: return "standard";
            case ACTIVITY_TYPE_HOME: return "home";
            case ACTIVITY_TYPE_RECENTS: return "recents";
            case ACTIVITY_TYPE_ASSISTANT: return "assistant";
            case ACTIVITY_TYPE_DREAM: return "dream";
        }
        return String.valueOf(applicationType);
    }
    
    public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) {
        switch (alwaysOnTop) {
            case ALWAYS_ON_TOP_UNDEFINED: return "undefined";
            case ALWAYS_ON_TOP_ON: return "on";
            case ALWAYS_ON_TOP_OFF: return "off";
        }
        return String.valueOf(alwaysOnTop);
    }
}
//frameworks/base/core/java/android/view/Surface.java
public class Surface implements Parcelable {
    public static String rotationToString(int rotation) {
        switch (rotation) {
            case Surface.ROTATION_0: {
                return "ROTATION_0";
            }
            case Surface.ROTATION_90: {
                return "ROTATION_90";
            }
            case Surface.ROTATION_180: {
                return "ROTATION_180";
            }
            case Surface.ROTATION_270: {
                return "ROTATION_270";
            }
            default: {
                return Integer.toString(rotation);
            }
        }
    }
}

当我们调用如下方法

 Log.i(TAG, "getWindowInfo: config = " + getResources().getConfiguration());

或者通过dumpsys window windows导出当前所有窗口的堆栈信息,都可以得到和Configuration类相关的以下信息:

config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w764dp h324dp 480dpi nrml long land finger -keyb/h/h -nav/h winConfig={ mBounds=Rect(0, 0 - 2400, 1080) mAppBounds=Rect(107, 0 - 2400, 1080) mMaxBounds=Rect(0, 0 - 2400, 1080) mDisplayRotation=ROTATION_90 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_90} s.2 fontWeightAdjustment=0mThemeChanged= 0, mThemeChangedFlags= 0, mFlipFont= 0, mAccessibleChanged= -1, mUxIconConfig= 3468921665126662176, mMaterialColor= 0, mUserId= 0, mFontUserId= 0, mFontVariationSettings= 226, mFoldingAngle = -1.0, mIconPackName= , mDarkModeBackgroundMaxL= 0.0, mDarkModeDialogBgMaxL= 27.0, mDarkModeForegroundMinL= 100.0, mOplusConfigType= 1, mOplusChangedConfigs= 0, OpSans= 0, mBurmeseFontFlag= 2, mFlag= 0, mPuttDisplayFlag= -1}

这里我们重点关注和WindowConfiguration相关的信息:

winConfig={ mBounds=Rect(0, 0 - 2400, 1080) mAppBounds=Rect(107, 0 - 2400, 1080) mMaxBounds=Rect(0, 0 - 2400, 1080) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_90}
  • mBounds=Rect(0, 0 - 2400, 1080):屏幕尺寸
  • mAppBounds=Rect(107, 0 - 2400, 1080):窗口可显示的安全区域,此属性会影响应用具体加载那个layout下面的布局文件,系统会优先选择尺寸最接近2293x1080的布局文件。
  • mMaxBounds=Rect(0, 0 - 2400, 1080):窗口可显示的最大区域
  • mWindowingMode=fullscreen:窗口为全屏模式
  • mDisplayWindowingMode=fullscreen:屏幕设备窗口为全屏模式
  • mActivityType=standard:页面类型未定义
  • mAlwaysOnTop=undefined:窗口悬浮模式未定义
  • mRotation=ROTATION_90:屏幕设备的旋转角度为90度

借助这些属性,开发者能够更好地适配不同的设备配置和屏幕状态,确保应用在不同环境下的一致性和优化。

四、修改WindowConfiguration的配置信息,刷新窗口UI视图

4.1 通过adb 修改屏幕旋转角度

我们可以通过以下指令获取当前屏幕的旋转角度

adb shell settings get system user_rotation #0:自然方向(竖屏)1:右旋转 90 度(横屏)2:倒转 180 度(反向竖屏)3:左旋转 270 (横屏)

还可以通过如下配置修改当前屏幕的旋转角度

adb shell settings put system user_rotation <value>

4.2 实现原理

当我们修改system数据库中的user_rotation字段的时候,会触发以下代码逻辑。

frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java

//frameworks/base/core/java/android/provider/Settings.java
public final class Settings {
        public static final String USER_ROTATION = "user_rotation";
}
public class DisplayRotation {

    private final WindowManagerService mService;

    private class SettingsObserver extends ContentObserver {
        SettingsObserver(Handler handler) {
            super(handler);
        }

        void observe() {
            final ContentResolver resolver = mContext.getContentResolver();
			...代码省略...
			//注释1,监听system数据库user_rotation字段的变化
            resolver.registerContentObserver(Settings.System.getUriFor(
                    Settings.System.USER_ROTATION), false, this,
                    UserHandle.USER_ALL);
            updateSettings();
        }

        @Override
        public void onChange(boolean selfChange) {
        	//注释2,判断设置是否发生了变化,如果发生了变化调用WMS的updateRotation方法
            if (updateSettings()) {
                mService.updateRotation(true /* alwaysSendConfiguration */,
                        false /* forceRelayout */);
            }
        }
    }
    
    private boolean updateSettings() {
        final ContentResolver resolver = mContext.getContentResolver();
        boolean shouldUpdateRotation = false;
        synchronized (mLock) {
			...代码省略...
            //获取当前屏的旋转角度
            final int userRotation = Settings.System.getIntForUser(resolver,
                    Settings.System.USER_ROTATION, Surface.ROTATION_0,
                    UserHandle.USER_CURRENT);
            if (mUserRotation != userRotation) {
                mUserRotation = userRotation;
                shouldUpdateRotation = true;
            }
			...代码省略...
        return shouldUpdateRotation;
    }

}

在注释1处DisplayRotation类会监听system数据库的user_rotation字段的变化,当该字段发生变化的时候,会在注释2处触发WindowManagerServices的updateRotation方法。

frameworksbase/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    @Override
    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
    }
    private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
		...代码省略...
        try {
            synchronized (mGlobalLock) {
                boolean layoutNeeded = false;
                final int displayCount = mRoot.mChildren.size();
                for (int i = 0; i < displayCount; ++i) {
                    final DisplayContent displayContent = mRoot.mChildren.get(i);
                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");
                    final boolean rotationChanged = displayContent.updateRotationUnchecked();
                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);

                    if (rotationChanged) {
                        mAtmService.getTaskChangeNotificationController()
                                .notifyOnActivityRotation(displayContent.mDisplayId);
                    }

                    if (!rotationChanged || forceRelayout) {
                        displayContent.setLayoutNeeded();
                        layoutNeeded = true;
                    }
                    if (rotationChanged || alwaysSendConfiguration) {
                        displayContent.sendNewConfiguration();
                    }
                }

                if (layoutNeeded) {
                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                            "updateRotation: performSurfacePlacement");
                    mWindowPlacerLocked.performSurfacePlacement();
                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

喜报 | 知从科技荣获 “AutoSec 安全之星 - 优秀汽车软件供应链安全方案奖”

近日&#xff0c;「AutoSec 2024第八届中国汽车网络安全周暨第五届智能汽车数据安全展」在上海盛大举行。本届大会由谈思实验室和谈思汽车主办、上海市车联网协会联合主办&#xff0c;以汽车“网络数据安全、软件安全、功能安全”为主题&#xff0c;设置了“31X”模式&#xff…

关于 PC打开“我的电脑”后有一些快捷如腾讯视频、百度网盘、夸克网盘、迅雷等各种捷方式在磁盘驱动器上面统一删除 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/142029325 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

numpy(基于Numpy外文文档的学习)

学习目标&#xff1a; Understand the difference between one-, two- and n-dimensional arrays in NumPy; Understand how to apply some linear algebra operations to n-dimensional arrays without using for-loops;&#xff08;调用一些简单的方法&#xff09; Underst…

外包干了三年,快要废了。。。

先简单说一下自己的情况&#xff0c;普通本科&#xff0c;在外包干了3年多的功能测试&#xff0c;这几年因为大环境不好&#xff0c;我整个人心惊胆战的&#xff0c;怕自己卷铺盖走人了&#xff0c;我感觉自己不能够在这样蹉跎下去了&#xff0c;长时间呆在一个舒适的环境真的会…

Docker 部署 Redis (图文并茂超详细)

部署 Redis ( Docker ) [Step 1] : 拉取 Redis 镜像, 推荐使用 7 的 Redis 版本 docker pull redis:7.0.12[Step 2] : 创建 Redis 相关目录 ➡️ 启动 Redis 容器 ➡️ 拷贝文件 ➡️ 授权文件夹 ➡️ 删除容器 # 创建 Redis 相关目录 mkdir -p /data/redis/{conf,data,log…

写的一致性问题之失效模式

文章目录 1、先删除redis缓存&#xff0c;再写入mysql&#xff1a;1.1、高并发情况下分析出现的问题 2、先写入mysql&#xff0c;再删除redis缓存 失效模式存在的问题&#xff1a;在事务提交之前可能会有其他读操作重新把旧数据放入redis缓存中 1、先删除redis缓存&#xff0c;…

深入解析全连接层:PyTorch 中的 nn.Linear、nn.Parameter 及矩阵运算

文章目录 数学概念&#xff08;全连接层&#xff0c;线性层&#xff09;nn.Linear()nn.Parameter()Q1. 为什么 self.weight 的权重矩阵 shape 使用 ( out_features , in_features ) (\text{out\_features}, \text{in\_features}) (out_features,in_features)而不是 ( in_featur…

Bev pool 加速(2):自定义c++扩展

文章目录 1. c++扩展2. 案例2.1 案例12. 1.1 代码实现(1) c++ 文件(2) setup.py编写(3) python 代码编写2.2 案例22.2.1 模型搭建2.2.2 c++ 扩展实现(1)c++ 扩展代码(2)setup.py编写(3)python 调用c++扩展在bevfusion论文中,将bev_pooling定义为view transform中的效率瓶…

PROTOTYPICAL II - The Practice of FPGA Prototyping for SoC Design

The Art of the “Start” The semiconductor industry revolves around the “start.” Chip design starts lead to more EDA tool purchases, more wafer starts, and eventually to more product shipments. Product roadmaps develop to extend shipments by integrating…

FloodFill算法

文章目录 1. 图像渲染&#xff08;733&#xff09;2. 岛屿数量&#xff08;200&#xff09;3. 岛屿的最大面积&#xff08;695&#xff09;4. 被围绕的区域&#xff08;130&#xff09; 1. 图像渲染&#xff08;733&#xff09; 题目描述&#xff1a; 算法原理&#xff1a; …

DAY13信息打点-Web 应用源码泄漏开源闭源指纹识别GITSVNDS备份

#知识点 0、Web架构资产-平台指纹识别 1、开源-CMS指纹识别源码获取方式 2、闭源-习惯&配置&特性等获取方式 3、闭源-托管资产平台资源搜索监控 演示案例&#xff1a; ➢后端-开源-指纹识别-源码下载 ➢后端-闭源-配置不当-源码泄漏 ➢后端-方向-资源码云-源码泄漏 …

1、https的全过程

目录 一、概述二、SSL过程如何获取会话秘钥1、首先认识几个概念&#xff1a;2、没有CA机构的SSL过程&#xff1a;3、没有CA机构下的安全问题4、有CA机构下的SSL过程 一、概述 https是非对称加密和对称加密的过程&#xff0c;首先建立https链接需要经过两轮握手&#xff1a; T…

算法提高模板强连通分量tarjan算法

AC代码&#xff1a; #include<bits/stdc.h>using namespace std;typedef long long ll; const int MOD 998244353; const int N 2e5 10;//强联通分量模板 //tarjan算法 vector<int>e[N]; int n, m, cnt; int dfn[N], low[N], ins[N], idx; int bel[N];//记录每…

Redis高可用,Redis性能管理

文章目录 一&#xff0c;Redis高可用&#xff0c;Redis性能管理二&#xff0c;Redis持久化1.RDB持久化1.1触发条件&#xff08;1&#xff09;手动触发&#xff08;2&#xff09;自动触发 1.2 Redis 的 RDB 持久化配置1.3 RDB执行流程(1) 判断是否有其他持久化操作在执行(2) 父进…

Chainlit集成Langchain并使用通义千问实现文生图网页应用

前言 本文教程如何使用通义千问的大模型服务平台的接口&#xff0c;实现图片生成的网页应用&#xff0c;主要用到的技术服务有&#xff0c;chainlit 、 langchain、 flux。合利用了大模型的工具选择调用能力。实现聊天对话生成图片的网页应用。 阿里云 大模型服务平台百炼 API…

R语言统计分析——功效分析3(相关、线性模型)

参考资料&#xff1a;R语言实战【第2版】 1、相关性 pwr.r.test()函数可以对相关性分析进行功效分析。格式如下&#xff1a; pwr.r.test(n, r, sig.level, power, alternative) 其中&#xff0c;n是观测数目&#xff0c;r是效应值&#xff08;通过线性相关系数衡量&#xff0…

NAT技术+代理服务器+内网穿透

NAT技术 IPv4协议中&#xff0c;会存在IP地址数量不充足的问题&#xff0c;所以不同的子网中会存在相同IP地址的主机。那么就可以理解为私有网络的IP地址并不是唯一对应的&#xff0c;而公网中的IP地址都是唯一的&#xff0c;所以NAT&#xff08;Network Address Translation&…

跨平台集成:在 AI、微服务和 Azure 云之间实现无缝工作流

跨平台集成在现代 IT 架构中的重要性 随着数字化转型的不断加速&#xff0c;对集成各种技术平台的需求也在快速增长。在当今的数字世界中&#xff0c;组织在复杂的环境中执行运营&#xff0c;其中多种技术需要无缝协作。环境的复杂性可能取决于业务的性质和组织提供的服务。具…

Windows更新之后任务栏卡死?桌面不断闪屏刷新?

前言 小白这几天忙于工作&#xff0c;更新就变得异常缓慢。但就算这么忙的情况下&#xff0c;晚上休息的时间还是会给小伙伴们提供咨询和维修服务。 这不&#xff0c;就有一个小伙伴遇到了个很奇怪的问题&#xff1a;电脑Windows更新之后&#xff0c;任务栏点了没反应&#xf…

深入理解Java虚拟机:Jvm总结-Java内存区域与内存溢出异常

第二章 Java内存区域与内存溢出异常 2.1 意义 对于C、C程序开发来说&#xff0c;程序员需要维护每一个对象从开始到终结。Java的虚拟自动内存管理机制&#xff0c;让java程序员不需要手写delete或者free代码&#xff0c;不容易出现内存泄漏和内存溢出问题&#xff0c;但是如果…