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

news2024/12/23 17:22:20

前言

在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.coloradmin.cn/o/2130823.html

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

相关文章

性能测试的复习2-jmeter的搭建、使用、参数化

通过网盘分享的文件&#xff1a;性能测试共享文件 链接: https://pan.baidu.com/s/1A4Nc8C5Xp6qxQ5QFtecK8g?pwds73c 提取码: s73c 1、性能测试工具 2、jmeter环境搭建 3、jmeter的基本使用 4、jmeter的参数化

strncpy函数的使用和模拟实现

目录 1.头文件 2.strncpy函数功能 2.1情况二&#xff1a; 3.strncpy函数&#xff08;模拟实现&#xff09; 方源一把抓住VS2022&#xff0c;催动春秋产的气息&#xff0c;顷刻炼化&#xff01; 1.头文件 strncpy函数的使用需要包括头文件<string.h> #include<string…

Windows系统好用软件推荐

uTools uTools官网&#xff1a;https://u.tools/download/ 功能介绍&#xff1a; 内置许多有用的插件、快速打开应用、复制图片保存等

4457E/4457F/4457G/4457K数字示波器

KEYSIGHT是德 4457E/4457F/4457G/4457K数字示波器 4457系列数字示波器共4个产品型号&#xff0c;产品带宽从1GHz到4GHz&#xff0c;采样率10GSa/s、20GSa/s&#xff0c;垂直分辨率8bit&#xff0c;存储深度2Gpts&#xff0c;最快波形捕获率120万个波形/秒&#xff0c;独创的An…

LIN帧显隐性电平和字节传输顺序理解

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

干耳屎硬掏不出来怎么办?质量最好的可视挖耳勺推荐

干耳朵的朋友都会有这样子的困扰&#xff0c;耳朵中的耳屎太硬挖不出来。用铁耳勺去挖会疼&#xff0c;还容易因为操作不当弄伤耳膜。而用棉签掏耳&#xff0c;只有越推越进去。所以当耳屎弄不出来是可以用专业的工具来挖取。市面上的可视挖耳勺通过内窥镜观察耳道中的情况。但…

电脑文件被删如何找回?选它,文件恢复又快又全面!

在我们的日常工作和生活中&#xff0c;文件是无比重要的存在。它可能是您精心撰写的报告&#xff0c;可能是珍贵的照片回忆&#xff0c;也可能是多年积累的工作资料。然而&#xff0c;有时一个不小心&#xff0c;文件可能就被我们删除了&#xff0c;那种焦急和无奈想必您也曾体…

解锁阿尔茨海默病(AD)靶点密码,开启靶向治疗新篇章

前 言&#xff1a; 阿尔茨海默病&#xff08;AD&#xff09;是一种严重的神经退行性疾病&#xff0c;多发于高龄人群&#xff0c;主要表现为记忆、思维、分析判断、视空间辨认、情绪等障碍。从实验室到临床应用的过程充满挑战。阿尔茨海默症新型疗法的开发主要聚焦于靶向Aβ、…

Percona Toolkit 神器全攻略(性能类)

Percona Toolkit 神器全攻略&#xff08;性能类&#xff09; Percona Toolkit 神器全攻略系列共八篇&#xff0c;前文回顾&#xff1a; 前文回顾Percona Toolkit 神器全攻略Percona Toolkit 神器全攻略&#xff08;实用类&#xff09;Percona Toolkit 神器全攻略&#xff08;配…

STM32+FATFS+SD卡+RTC(生成.CSV格式文件)

一、简介 实验目的&#xff1a;在SD卡上挂载文件系统&#xff0c;实时记录压力传感器采集到的数据&#xff1b;且在表格第一排记录采集时间&#xff1b; 因为前面文章包含了除RTC之外的所有的代码&#xff0c;此文章只放RTC代码。 二、工程源码 RTC.c #include "sys.h…

人工智能|集成学习——混合专家模型 (MoE)

随着 Mixtral 8x7B (announcement, model card) 的推出&#xff0c;一种称为混合专家模型 (Mixed Expert Models&#xff0c;简称 MoEs) 的 Transformer 模型在开源人工智能社区引起了广泛关注。在本篇博文中&#xff0c;我们将深入探讨 MoEs 的核心组件、训练方法&#xff0c;…

arcgisPro绘制平行线、垂直线段

1、绘制一条线 2、点击【创建要素】按钮&#xff0c;选择线&#xff0c;点一个点后&#xff0c;将鼠标移至需要对其的线上&#xff0c;并右击&#xff0c;选择【平行】 3、移动一段距离后&#xff0c;完成绘制&#xff0c;可得到一条平行线 4、得到平行线 5、绘制垂直线&#x…

一文读懂:区块链的原理、技术、应用领域

引言 在当今数字化时代&#xff0c;区块链技术已经成为全球范围内备受瞩目的话题。从金融到供应链&#xff0c;从物联网到数字身份&#xff0c;区块链正在以惊人的速度渗透到各个行业&#xff0c;并在重塑着我们的社会和经济格局。 区块链最初因其作为比特币背后技术的而引起…

OrionX vGPU研发测试场景下最佳实践之SSH模式

开发机场景概述 目前很多企业在做AI开发的场景时&#xff0c;对GPU资源的管理都是非常简单粗暴的。他们大多都是以开发小组为管理单位、由运维以台为单位分配给开发工程师使用。而在AI开发中涉及开发的场景和测试的场景&#xff0c;很多是将开发测试甚至训练任务都放在一起来使…

<<编码>> 第 11 章 逻辑门电路--门电路 示例电路

作为门电路的继电器开关电路 info::操作说明 鼠标单击开关切换开合状态 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/code-hlchs-examples/assets/circuit/code-hlchs-ch11-06-relay-as-gate.txt 作为反相器的继电器开关电路 …

EPON光模块介绍

EPON光模块在依靠光纤网络实现快速可靠的数据传输、增强带宽能力和提高网络效率的过程中发挥着至关重要的作用。在这篇文章中&#xff0c;我们将深入研究EPON光模块的基本概念、各种类型、优点和局限性&#xff0c;全面了解它们在现代电信中的重要性。 EPON光模块的定义 EPON…

ZYNQ 入门笔记(二):动态时钟

文章目录 1 概述1.1 DRP1.2 AXI4-Lite 2 示例2.1 单时钟输出2.2 多时钟输出 3 参考文档 1 概述 Clocking Wizard 可通过配置内部寄存器动态调整输出频率&#xff0c;配置接口可选 DRP 或 AXI4-Lite&#xff0c;其中 AXI4-Lite 实际上是对 DRP 接口的封装 1.1 DRP 通过 DRP 接…

Python文件操作:上下文管理器(with语句)②

文章目录 1. 上下文管理器概述1.1 什么是上下文管理器&#xff1f;1.2 为什么使用上下文管理器&#xff1f;1.3 with语句的基本语法 2. 文件操作中的上下文管理器2.1 使用with语句打开文件2.2 读取文件2.2.1 读取整个文件内容2.2.2 逐行读取文件 2.3 写入文件2.3.1 覆盖写入2.3…

JavaWeb使用web.xml配置Servlet路径映射的相关操作以及易错问题分析与解决

前言 我们在使用Servlet创建JavaWeb项目时&#xff0c;想要绑定url路径和Servlet的映射关系&#xff0c;需要在web.xml中配置映射关系。Servlet从2.5版本开始支持注解。具体来说&#xff0c;Servlet 2.5引入了注解配置方式&#xff0c;使得Servlet应用程序的配置更加简单、灵活…

文档智能:OCR+Rocketqa+layoutxlm

此次先记录LayoutLMv2&#xff0c;梳理相关论文&#xff0c;记录如下&#xff1a; 首先认识一下 visually-rich document understanding tasks → \to → VrDU 其次&#xff0c;the text fields of interest&#xff0c;与图像识别的感兴趣区域 region of Interest 类似&…