资深架构师:深入聊聊获取屏幕高度这件事

小米获取屏幕高度不准确-小米获取屏幕高度的兼容方案 今天发现,小米8手机获取屏幕高度的方法不准确,进过一些测试以后发现是虚拟导航按键出了问题。 这里获取屏幕高度的方法用的是 public static int getScreenHeight(Activity activity) { DisplayMetrics dm = new DisplayMetrics(); activity.getWindowManag... 阅读详情

回顾过去

说起获取屏幕高度,不知道你是如何理解这个高度范围的?是以应用显示区域高度作为屏幕高度还是手机屏幕的高度。

那么我们先看一下平时使用获取高度的方法:

public static int getScreenHeight(Context context) {
	WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
	Display display = wm.getDefaultDisplay();
	DisplayMetrics dm = new DisplayMetrics();
	display.getMetrics(dm);
	return dm.heightPixels;
}

//或
public static int getScreenHeight(Context context) {
	WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
	Point point = new Point();
	wm.getDefaultDisplay().getSize(point);
	return point.y;
}

// 或
public static int getScreenHeight(Context context) {
	return context.getResources().getDisplayMetrics().heightPixels;
}
// 貌似还有更多的方法

以上三种效果一致,只是写法略有不同。

当然你或许使用的是这种:

public static int getScreenHeight(Context context) {
	WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
	Display display = wm.getDefaultDisplay();
	DisplayMetrics dm = new DisplayMetrics();
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
		display.getRealMetrics(dm);
	} else {
		display.getMetrics(dm);
	}
	return dm.heightPixels;
}
// 其他几种写法大同小异
...

这个方法判断了系统大于等于Android 4.2时,使用getRealMetrics(getRealSize)来获取屏幕高度。那么这里发生了什么,为什么会这样?

其实在Andoird 4.0时,引入了虚拟导航键,如果你继续使用getMetrics之类的方式,获取的高度是去除了导航栏的高度的。

当时因为在4.0和4.2之间还没有的getRealMetrics这个方法,所以甚至需要添加下面的适配代码:

try {
     heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(display);
} catch (Exception e) {
}

现在不会还有人适配4.4甚至5.0一下的机子了吧,不会吧不会吧。。。所以历史的包袱可以去掉了。

上面方法名都是getScreenHeight,可是这个高度范围到底和你需要的是否一致。这个需要开发时注意,我的习惯是ScreenHeight指应用显示的高度,不包括导航栏(非全屏下),RealHeight来指包含导航栏和状态栏的高度(getRealMetrics)。

PS:以前也使用过AndroidUtilCode这个工具库,里面将前者方法名定义为getAppScreenHeight,后者为getScreenHeight。也是很直观的方法。

下文中我会以自己的习惯,使用ScreenHeight和RealHeight来代表两者。

我印象中华为手机很早就使用了虚拟导航键,如下图(图片来源):

华为手机

比较特别的是,当时华为的导航栏还可以显示隐藏,注意图中左下角的箭头。点击可以隐藏,上滑可以显示。即使这样,使用getScreenHeight也可以准确获取高度,隐藏了ScreenHeight就等于RealHeight。

上述的这一切在“全面屏”时代没有到来之前,没有什么问题。

立足当下

小米MIX的发布开启了全面屏时代(16年底),以前的手机都是16:9的,记得雷布斯在发布会上说过,他们费了很大的力气说服了谷歌去除了16:9的限制(从Android 7.0开始) MIX 2发布会

MIX 2发布会

全面屏手机是真的香,不过随之也带来适配问题。首当其冲的就是刘海屏,各家有各自的获取刘海区域大小的方法。主要原因还是国内竞争的激烈,各家为了抢占市场,先于谷歌定制了自己的方案。这一点让人想起了万恶的动态权限适配。。。

其实在刘海屏之下,还隐藏一个导航栏的显示问题,也就是本篇的重点。全面屏追求更多的显示区域,随之带来了手势操作。在手势操作模式下,导航栏是隐藏状态。

本想着可以和上面提到的华为一样,隐藏获取的就是RealHeight,显示就是减去导航栏高度的ScreenHeight。然而现实并不是这样,下表是我收集的一些全面屏手机各高度的数据。

机型系统ScreenHeightRealHeightNavigationBarStatusBar是否有刘海
vivo Z3xFuntouch OS_10(Android 10)2201(2075)228012684是
Xiaomi MIX 2sMIUI 12(Android 10)2030(2030)216013076否
Redmi Note 8ProMIUI 11.0.3(Android 10)2134(2134)234013076是
Redmi K30 5GMIUI 12.0.3(Android 10)2175(2175)240013095是
Honor 10 LiteEMUI 10(Android 10)2259(2139)234012081是
华为畅享 20EMUI 10.1.1(Android 10)1552(1472)16008048是
OPPO Find XColorOS 7.1(Android 10)2340(2208)234013296否
OnePlus 6H2OS 10.0.8(Android 10)2201(2159,2075)2280126(42)80否

ScreenHeight一栏中括号内表示显示导航栏时获取的屏幕高度。

大致的规律总结如下:

  • 在有刘海的手机上,ScreenHeight不包含状态栏高度。
  • 小米手机在隐藏显示导航栏时,ScreenHeight不变,且不包含导航栏高度。

其中vivo手机,屏幕高度加状态栏高度大于真实高度(2201 + 84 > 2280)。本以为差值79是刘海高度,但查看vivo文档后发现,vivo刘海固定27dp(81px),也还是对不上。。。

一加6最奇怪,三种设置模式。使用侧边全屏手势时底部有一个小条,NavigationBar高度变为42。(2159 + 42 = 2075 + 126 = 2201)也就是说这种模式也属于有导航栏的情况。

一加6导航设置页

这时如果你需要获取准确的ScreenHeight,只有通过RealHeight - NavigationBar来实现了。

所以首先需要判断当前导航栏是否显示,再来决定是否减去NavigationBar高度。

先看看老牌的判断方法如下:

public boolean isNavigationBarShow(){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        Point realSize = new Point();
        display.getSize(size);
        display.getRealSize(realSize);
        return realSize.y!=size.y;
    } else {
        boolean menu = ViewConfiguration.get(this).hasPermanentMenuKey();
        boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
        if(menu || back) {
            return false;
        }else {
            return true;
        }
    }
}

此方法通过比较ScreenHeight和RealHeight是否相等来判断。如果对比上面表中的数据,那只有OPPO Find X可以判断成功。也有一些方法通过ScreenHeight和RealHeight差值来计算导航栏高度。显然这些方法已无法再使用。

所以搜索了一下相关信息,得到了下面的代码:

	/**
     * 是否隐藏了导航键
     *
     * @param context
     * @return
     */
    public static boolean isNavBarHide(Context context) {
        try {
            String brand = Build.BRAND;
            // 这里做判断主要是不同的厂商注册的表不一样
            if (!StringUtils.isNullData(brand) && (Rom.isVivo() || Rom.isOppo())) {
                return Settings.Secure.getInt(context.getContentResolver(), getDeviceForceName(), 0) != 0;
            } else if (!StringUtils.isNullData(brand) && Rom.isNokia()) {
                //甚至 nokia 不同版本注册的表不一样, key 还不一样。。。
                return Settings.Secure.getInt(context.getContentResolver(), "swipe_up_to_switch_apps_enabled", 0) == 1
                        || Settings.System.getInt(context.getContentResolver(), "navigation_bar_can_hiden", 0) != 0;
            } else
                return Settings.Global.getInt(context.getContentResolver(), getDeviceForceName(), 0) != 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 各个手机厂商注册导航键相关的 key
     *
     * @return
     */
    public static String getDeviceForceName() {
        String brand = Build.BRAND;
        if (StringUtils.isNullData(brand))
            return "navigationbar_is_min";
        if (brand.equalsIgnoreCase("HUAWEI") || "HONOR".equals(brand)) {
            return "navigationbar_is_min";
        } else if (Rom.isMiui()||Rom.check("XIAOMI")) {
            return "force_fsg_nav_bar";
        } else if (Rom.isVivo()) {
            return "navigation_gesture_on";
        } else if (Rom.isOppo()) {
            return "hide_navigationbar_enable";
        } else if (Rom.check("samsung")) {
            return "navigationbar_hide_bar_enabled";
        } else if (brand.equalsIgnoreCase("Nokia")) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
                return "navigation_bar_can_hiden";
            } else {
                return "swipe_up_to_switch_apps_enabled";
            }
        } else {
            return "navigationbar_is_min";
        }
    }

可以看到包含了华为、小米、vivo、oppo 、三星甚至诺基亚的判断。这就是适配的现实状况,不要妄想寻找什么通用方法,老老实实一个个判断吧。毕竟幺蛾子就是这些厂家搞出来的,厂家魔改教你做人。

这种方法在上面的测试机中都亲测准确有效。

不过这个判断方法不够严谨,比如其他品牌手机使用此方法,那么结果都是false。用这样的结果来计算高度显得不够严谨。

根据前面提到问题发生的原因是全面屏带来的(7.0及以上)。所以我们可以先判断是否是全面屏手机(屏幕长宽比例超过1.86以上),然后判断是否显示导航栏,对于不确定的机型,我们还是使用原先的ScreenHeight。尽量控制影响范围。

我整理的代码如下(补充了一加、锤子手机判断):

/**
 * @author weilu
 **/
public class ScreenUtils {

	private static final String BRAND = Build.BRAND.toLowerCase();

	public static boolean isXiaomi() {
		return Build.MANUFACTURER.toLowerCase().equals("xiaomi");
	}

	public static boolean isVivo() {
		return BRAND.contains("vivo");
	}

	public static boolean isOppo() {
		return BRAND.contains("oppo") || BRAND.contains("realme");
	}

	public static boolean isHuawei() {
		return BRAND.contains("huawei") || BRAND.contains("honor");
	}

        public static boolean isOneplus(){
		return BRAND.contains("oneplus");
	}

	public static boolean isSamsung(){
		return BRAND.contains("samsung");
	}

	public static boolean isSmartisan(){
		return BRAND.contains("smartisan");
	}

	public static boolean isNokia() {
		return BRAND.contains("nokia");
	}

    	public static boolean isGoogle(){
		return BRAND.contains("google");
	}

	public static int getRealScreenHeight(Context context) {
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();
		DisplayMetrics dm = new DisplayMetrics();
		display.getRealMetrics(dm);
		return dm.heightPixels;
	}

	public static int getRealScreenWidth(Context context) {
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();
		DisplayMetrics dm = new DisplayMetrics();
		display.getRealMetrics(dm);
		return dm.widthPixels;
	}

	public static int getScreenHeight(Context context) {
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		Display display = wm.getDefaultDisplay();
		DisplayMetrics dm = new DisplayMetrics();
		display.getMetrics(dm);
		return dm.heightPixels;
	}

	/**
	 * 判断设备是否显示NavigationBar
	 *
	 * @return 其他值 不显示 0显示 -1 未知
	 */
	public static int isNavBarHide(Context context) {
		// 有虚拟键,判断是否显示
		if (isVivo()) {
			return vivoNavigationEnabled(context);
		}
		if (isOppo()) {
			return oppoNavigationEnabled(context);
		}
		if (isXiaomi()) {
			return xiaomiNavigationEnabled(context);
		}
		if (isHuawei()) {
			return huaWeiNavigationEnabled(context);
		}
                if (isOneplus()) {
			return oneplusNavigationEnabled(context);
		}
		if (isSamsung()) {
			return samsungNavigationEnabled(context);
		}
		if (isSmartisan()) {
			return smartisanNavigationEnabled(context);
		}
		if (isNokia()) {
			return nokiaNavigationEnabled(context);
		}
     		if (isGoogle()) {
			// navigation_mode 三种模式均有导航栏,只是高度不同。
			return 0;
		}
		return -1;
	}

	/**
	 * 判断当前系统是使用导航键还是手势导航操作
	 *
	 * @param context
	 * @return 0 表示使用的是虚拟导航键,1 表示使用的是手势导航,默认是0
	 */
	public static int vivoNavigationEnabled(Context context) {
		return Settings.Secure.getInt(context.getContentResolver(), "navigation_gesture_on", 0);
	}

	public static int oppoNavigationEnabled(Context context) {
		return Settings.Secure.getInt(context.getContentResolver(), "hide_navigationbar_enable", 0);
	}

	public static int xiaomiNavigationEnabled(Context context) {
		return Settings.Global.getInt(context.getContentResolver(), "force_fsg_nav_bar", 0);
	}

	private static int huaWeiNavigationEnabled(Context context) {
		return Settings.Global.getInt(context.getContentResolver(), "navigationbar_is_min", 0);
	}

	/**
	 * @param context
	 * @return 0虚拟导航键  2为手势导航
	 */
	private static int oneplusNavigationEnabled(Context context) {
		int result = Settings.Secure.getInt(context.getContentResolver(), "navigation_mode", 0);
		if (result == 2) {
			// 两种手势 0有按钮, 1没有按钮
			if (Settings.System.getInt(context.getContentResolver(), "buttons_show_on_screen_navkeys", 0) != 0) {
				return 0;
			}
		}
		return result;
	}

	public static int samsungNavigationEnabled(Context context) {
		return Settings.Global.getInt(context.getContentResolver(), "navigationbar_hide_bar_enabled", 0);
	}

	public static int smartisanNavigationEnabled(Context context) {
		return Settings.Global.getInt(context.getContentResolver(), "navigationbar_trigger_mode", 0);
	}

	public static int nokiaNavigationEnabled(Context context) {
		boolean result = Settings.Secure.getInt(context.getContentResolver(), "swipe_up_to_switch_apps_enabled", 0) != 0
				|| Settings.System.getInt(context.getContentResolver(), "navigation_bar_can_hiden", 0) != 0;

		if (result) {
			return 1;
		} else {
			return 0;
		}
	}

	public static int getNavigationBarHeight(Context context){
		int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
		if (resourceId > 0) {
			return context.getResources().getDimensionPixelSize(resourceId);
		}
		return 0;
	}

	private static boolean isAllScreenDevice(Context context) {
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
			// 7.0放开限制,7.0以下都不为全面屏
			return false;
		} else {
			int realWidth = getRealScreenWidth(context);
			int realHeight = getRealScreenHeight(context);

			float width;
			float height;
			if (realWidth < realHeight) {
				width = realWidth;
				height = realHeight;
			} else {
				width = realHeight;
				height = realWidth;
			}
			// Android中默认的最大屏幕纵横比为1.86
			return height / width >= 1.86f;
		}
	}

	/**
	 * 获取去除导航栏高度的剩余高度(含状态栏)
	 * @param context
	 * @return
	 */
	public static int getScreenContentHeight(Context context) {

		if (isAllScreenDevice(context)) {

			int result = isNavBarHide(context);

			if (result == 0) {
				return getRealScreenHeight(context) - getNavigationBarHeight(context);
			} else if (result == -1){
				// 未知
				return getScreenHeight(context);
			} else {
				return getRealScreenHeight(context);
			}
		} else {
			return getScreenHeight(context);
		}

	}
}

有人会问,这些key都是哪里来的?毕竟我在厂商文档也没有翻到。

我能想到的办法是查看SettingsProvider,它是提供设置数据的Provider,分有Global、System、Secure三种类型,上面代码中可以看到不同品牌存放在的类型都不同。我们可以通过adb命令查看所有数据,根据navigation等关键字去寻找。比如查看Secure的数据:

	adb shell settings list secure

或者:

	ContentResolver cr = context.getContentResolver();
	Uri uri = Uri.parse("content://settings/secure/");
	Cursor cursor = cr.query(uri, null, null, null, null);
	while (cursor.moveToNext()) {
		String name = cursor.getString(cursor.getColumnIndex("name"));
		String value = cursor.getString(cursor.getColumnIndex("value"));
		Log.d("settings:", name + "=" + value);
	}
	cursor.close();		

这样如果有上面兼容不到的机型,可以使用这个方法适配。也欢迎你的补充反馈。

费了这么大的劲获取到了准确的高度,可能你会说,还不如直接获取ContentView的高度:

	public static int getContentViewHeight(Activity activity) {
		View contentView = activity.getWindow().getDecorView().findViewById(android.R.id.content);
		return contentView.getHeight();
	}

这个结果和上述计算的高度一致,唯一的限制是需要在onWindowFocusChanged之后调用,否则高度为0。这个我们可以根据实际情况自行选用。

已知问题

  • 网上有许多同类代码,发现会将vivo和oppo都使用navigation_gesture_on这一个key。我在oppo Find x中发现此key并不存在,不知是否和系统版本有关。如果是的话,又需要判断oppo的系统版本了。

  • 上面提到的获取导航栏高度的方法在部分手机中无效,无效的原因是因为导航栏隐藏时,获取高度就为0。所以判断是否显示导航栏是关键。

  • 刘海的出现,很多人会吐槽丑,所以厂家想到了隐藏刘海的方式(掩耳盗铃),比如下面是Redmi K30的设置页面:

设置刘海显示页

第二种没啥特别,就是状态栏强制为黑色。这里我怀疑因为这个设置,导致在有刘海的手机上,ScreenHeight不包含状态栏高度。

最糟糕的是第三种,隐藏后状态栏在刘海外。例如Redmi K30在开启后,ScreenHeight 为2174,RealHeight为2304,而关闭时为2175 和 2400。这下连万年不变的RealHeight也变化了,这太不real了,大家自行体会。不过目前发现未影响适配方案,不知其他手机如何。

对于是否隐藏刘海,其实也是有各家的判断的,比如小米:

	// 0:显示刘海,1:隐藏刘海
	Settings.Global.getInt(context.getContentResolver(), "force_black", 0);
  • 有些App会使用修改density的屏幕适配方案,这会影响获取导航栏高度的方法。比如130px的导航栏适配后获取到的是136px。所以这里需要使用getSystem中的density转换回去:
	public static int getNavigationBarHeight(Context context){
		int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
		if (resourceId > 0) {
			int height = context.getResources().getDimensionPixelSize(resourceId);
			// 兼容屏幕适配导致density修改
			float density = context.getResources().getDisplayMetrics().density;
			if (DENSITY != density) {
				return dpToPx(px2dp(context, height));
			}
			return height;
		}
		return 0;
	}

	public static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;

	public static int dpToPx(int dpValue) {
		return (int) (dpValue * DENSITY + 0.5f);
	}

	public static int px2dp(Context context, int px) {
		return (int) (px / context.getResources().getDisplayMetrics().density + 0.5);
	}

getSystem源码如下:

	/**
     * Return a global shared Resources object that provides access to only
     * system resources (no application resources), is not configured for the
     * current screen (can not use dimension units, does not change based on
     * orientation, etc), and is not affected by Runtime Resource Overlay.
     */
    public static Resources getSystem() {
        synchronized (sSync) {
            Resources ret = mSystem;
            if (ret == null) {
                ret = new Resources();
                mSystem = ret;
            }
            return ret;
        }
    }

它不受资源覆盖的影响,我们可以通过它将值转换回来。

展望未来

本篇看似聊的获取高度这件事,其实伴随导航栏的发展演进,核心是是如何判断导航栏是否显示。

通过上面的介绍,总结一下就是在“全面屏时代”,如果你想获取屏幕高度,就不要使用ScreenHeight了。否则会出现UI展示上的问题。而且这种问题,线上也不会崩溃,难以发现。以前在支付宝中就发现过 PopupWindow弹出高度不正确的问题,过了好久才修复了。

至于屏幕宽度,也不清楚随着折叠屏、环绕屏的到来会不会造成影响。但愿不要吧,碎片化原来越严重了。。。

最后,如果本文对你有启发有帮助,点个赞可好?

从瓦格纳的‘怪杰’性格,聊聊技术圈那些‘天才与疯子’的边界在哪里? 本文探讨了技术圈中天才与疯子之间的微妙边界,分析了那些天赋异禀却难以合作的‘技术怪杰’的特质与管理策略。通过真实案例和评估框架,揭示了如何在创新与团队协作之间找到平衡,为技术领导者提供了实用的管理工具和策略。 阅读详情

相关推荐

Squish GUI自动化测试实战:从对象识别到CI/CD集成

GUI自动化测试是软件质量保障的关键环节,其核心在于模拟用户操作并验证界面行为。传统基于图像识别或坐标定位的方法在面对复杂、动态变化的界面时往往显得脆弱,而基于对象识别的技术则通过直接访问应用程序内部控件树,实现了更稳定、高效的自动化。Squish作为一款企业级GUI自动化测试工具,正是这一技术的代表,它采用探针注入机制,能够精准识别Qt、Java、Windows、Web等多平台的自定义控件,显著提升了测试脚本的健壮性和执行速度。在工程实践中,Squish通过对象映射管理、数据驱动测试和页面对象模型等设计,

weixin_28834169的博客 359

聊聊获取屏幕高度这件事

说起获取屏幕高度,不知道你是如何理解这个高度范围的?是以应用显示区域高度作为屏幕高度还是手机屏幕的高度。

唯鹿的博客 4万+

工程师工作台效率系统:从混乱到可控的硬件开发实践指南

在硬件开发与电子工程领域,工作环境管理是影响研发效率与质量的关键因素。其核心原理在于通过优化物理空间与信息流的组织方式,降低认知负荷与操作摩擦,从而提升问题解决与创新验证的流畅度。从技术价值看,一套科学的工作台系统不仅能减少人为错误、加速调试周期,更是工程师思维模式与项目状态的直观映射,有助于在深度思考与动手实践间建立高效切换机制。典型的应用场景包括嵌入式系统开发、模拟/数字电路调试、PCB原型验证等硬件研发全流程。本文以硬件工程师工作台的“混乱美学”为切入点,深入探讨了如何构建兼顾秩序与创造力的效率系统,

weixin_42628573的博客 266

JS_js和jq获取屏幕高度、宽度的方法

一、js部分 1.获取屏幕尺寸 获取屏幕宽度:window.screen.width; //整个屏幕的宽度 获取屏幕高度:window.screen.height; //整个屏幕的高度 2.获取可用工作区尺寸 获取屏幕可用工作区域宽度:window.screen.availWidth; //pc端与上面两个一致,移动端除个别其他也一致(试一下即可) 获取屏幕可用工作区域高度:window.screen.availHeight; 3.获取body的宽高(不含边框) 获取网页内body

小歪博客 1万+

硬件工程师八大细分岗位详解:从芯片到整机的技术分工与职业选择

硬件工程作为电子系统设计的核心领域,涉及从芯片级到整机级的完整技术链条。其基本原理是通过电路设计、信号处理和功率管理等技术,将电子元件集成为功能完备的硬件系统。随着产品复杂度提升,硬件工程师岗位出现高度专业化分工,这种细分不仅提升了技术深度,更优化了团队协作效率。在工程实践中,信号完整性和电源完整性成为高速数字设计的两个关键技术挑战,直接影响系统稳定性。本文基于行业热词"硬件工程师"和"信号完整性",深入解析八大细分岗位的技术差异,帮助从业者明确职业发展方向,构建系统化的硬件设计思维。

weixin_33811539的博客 457

NLP学科内卷化:跨学科性衰退的实证诊断与破局路径

自然语言处理(NLP)作为人工智能核心分支,其发展正从多学科融合走向技术单极主导。本文基于25年顶会论文元数据、作者合作网络与引用图谱,系统揭示NLP在作者跨学科性、引用多样性、方法论融合度及问题定义边界四个维度的结构性收窄。研究发现:计算语言学、认知科学、语用学等基础领域持续退出主流,混合范式日益表面化,‘规则即装饰’‘理论即标签’现象普遍;同时,问题定义窄化为指标优化,导致经典语言学问题蒸发、人才能力断层。该趋势不仅削弱NLP的理论深度与可解释性,更在工业界引发语用失误、合规风险与AI Agent创新瓶

weixin_30666401的博客 466

获取屏幕高度

一、通过View提供的的方法获取高度的方式有两种: 1)当前显示的view直接获取当前view的宽高; 2)通过Activity的getWindow().findViewById(Window.ID_ANDROID_CONTENT)获取系统当前显示的view根(是一个framelayout对象),android绘制会将要绘制的view放置在framelayout中绘制。   二、通过Dis

silvia0427的专栏 1056

【社会科学】【管理科学】 第二十六章 评价管理——企业中通过评价实现人的管理方法和策略及行为01

编号类型领域评价人被评价人评价方法和策略评价控制的逐步推理思考的方程式及语言/话术/表情/姿态/动作/脸色/眼色关联知识法律法规和底线要求1绩效结果导向型评价绩效管理直接上级全体员工关键绩效指标法(KPI)与季度/年度复盘会推理方程式:核对期初目标(量化)→ 分析实际数据与目标差距 → 归因(外部/内部、能力/意愿)→ 共识下阶段改进点。 话术:“来看下我们Q2的业绩面板。你负责的A指标超额完成,值得肯定。但B指标有10%的缺口,你分析主要是什么原因?” 表情/姿态:坐在会议桌同侧,电脑屏幕或文

weixin_49199313的博客 625

Android获取屏幕高度的坑

安卓手机想要获取屏幕高度,有以下几个方法: 第一个我们先不讲,因为实测和后面2、4基本一样,况且网上说的少用的也少一开始我用的是方法4(因为他看起来最简单),发现在一些全面屏手机上高度会少了十几个像素,在普通手机上是准确的。 后来发现主要是虚拟按键的问题,会将虚拟按键的高度忽略掉。点击去看到他的说明是问题就在这个available上了。同理,还有方法,在Android4.4之后会隐藏掉状态栏的高度,注释里还写了一大堆,像来自Activity的请求在多窗口模式下会小于物理高度(这又是另一个坑了)正在上传…

yangaiyu的博客 2434

VSCode插件全攻略:5分钟搞定Mermaid流程图实时预览(含常见报错解决)

本文提供了一份详细的VSCode插件实战指南,帮助开发者快速配置Mermaid流程图实时预览环境。文章涵盖核心插件选择、高效工作流搭建,并重点解决了图表渲染失败、样式异常等常见报错问题,旨在提升技术文档的编写效率与可视化质量。

rust6ferris的博客 1488

Python中的串口通信库pyserial(基础)

pyserial是一个跨平台的库,可以在多个操作系统上使用,包括Windows、Linux和MacOS。:flushInput方法用于清除输入缓冲区中的所有数据,flushOutput方法用于清除输出缓冲区中的所有待发送数据。:PySerial允许在创建Serial对象后,通过修改对象的属性来设置串口参数,如波特率、数据位、校验位和停止位。同时,也提供了方法或属性来检查串口的状态,如是否已打开。:sendBreak方法用于向串口发送一个BREAK信号,这可以用于向连接的设备发送一个中断或重置信号。

weixin_44217158的博客 1万+

从抽象鹅漫画看硬件工程师的日常:FPGA设计中的幽默与实战

数字电路设计是计算机体系结构的基础,其核心在于通过硬件描述语言将逻辑功能映射到可编程器件。从寄存器传输级到门级网表的综合过程,体现了抽象层次在工程实践中的关键作用。这种抽象不仅提升了设计效率,更催生了硬件工程师独特的调试文化与工程哲学。在实际的FPGA和CPLD开发中,工程师常需面对信号完整性、时钟域同步等底层挑战,而状态机编码、同步器设计等技巧则直接关系到系统的可靠性与安全性。通过剖析接口协议、系统分层等场景,本文以幽默的视角切入,揭示了硬件设计中的常见陷阱与解决方案,为从事数字逻辑和半导体开发的工程师提

weixin_28724003的博客 283

SQL Server2008详细安装步骤(超详细步骤)

https://pan.baidu.com/s/1yvolqfU-AbiuGrIzblA7pA 提取码:lzw81.下载好安装包后解压到除C盘以外的磁盘,避免系统卡顿2.使用管理员身份打开安装程序注意:使用管理员身份打开时,此时如果显示以下画面属于正常现象,下载安装即可。因为.net现在有很多软件都需要,包括SQLSERVER2008,它里面有visual studio都要有net,电脑系统没有的话安装一下好了。3.选择全新安装或向现有安装添加新功能4.点击确定5.出现以下画面之后,输入产品密钥即可(密钥在

m0_67402774的博客 4万+

AI时代程序员如何重构核心价值:从代码实现到系统设计的转型之路

在软件开发领域,自动化工具和人工智能技术正深刻改变着传统的工作模式。从代码补全到测试生成,AI辅助编程工具通过理解上下文和自然语言指令,显著提升了开发效率。这一技术演进的核心价值在于将开发者从重复性编码任务中解放出来,使其能更专注于高层次的系统架构与问题定义。随着AI在编程各环节的渗透,程序员的核心技能重心正从语法实现转向需求抽象、架构设计和人机协同。特别是在系统设计阶段,开发者需要强化复杂业务逻辑的抽象能力,并掌握如何将模糊需求转化为精确的技术方案。这种转型不仅关乎个人技能升级,也影响着整个IT行业的人才

weixin_29596051的博客 283

防雷防浪涌电路设计

通信线路或者电源线路通常会铺设到户外,一旦线路铺到户外后,就需要考虑防雷的问题了,那么怎么设计保护电路,能够防止雷电等浪涌对电路的破坏呢?

manhuami2007的博客 1万+

支付宝支付(三):周期扣款实现注意细节

一、周期扣款实现说明 1、官方文档入口:https://opendocs.alipay.com/open/20190319114403226822/intro 2、根据官方文档说明,周期扣款有两种方式:先签约后代扣场景和支付后签约场景 3、周期扣款接入问题文档: a>https://opendocs.alipay.com/support/01rg24 b>https://opensupport.alipay.com/support/knowledge/50249/20160248753

新鲜雾霾的博客 5707

Claude Code自动模式默认开启:AI编程从辅助到接管的新范式

代码生成技术正从传统的命令式交互向预测式交互演进,其核心原理在于通过深度学习模型理解上下文,主动预测开发者意图。这一转变的技术价值在于显著减少认知摩擦,将开发者从重复性语法细节中解放出来,使其更专注于业务逻辑和架构设计。在实际应用场景中,AI编程助手能够实现代码风格与模式的一致性,促进团队知识传承,并充当实时安全编码提醒。Claude Code将自动模式设为默认,正是这一趋势的标志性事件,它意味着AI正从“按需调用”的工具,转变为“持续在场”的环境智能,深刻重塑开发工作流。

weixin_30417487的博客 342

华为OD机试双机位C卷-水库溃坝填补(Py/Java/C/C++/Js/Go)

华为OD机试(机考)双机位C卷 【水库溃坝填补】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。水库溃坝填补。

qq_45776114的博客 2110

AI编程工具选择:从Claude隐私争议到Coding Plan出海,看云端与本地化架构差异

在软件开发领域,AI辅助编程正成为提升效率的关键技术。其核心原理是通过机器学习模型理解代码上下文与开发者意图,自动生成或补全代码片段。这项技术的价值在于显著减少重复性编码工作,帮助开发者聚焦于架构设计与复杂逻辑。当前,AI编程工具主要分为云端服务化与本地边缘化两种架构模式,分别适用于不同应用场景。云端模式依托大型语言模型,提供强大的通用对话与推理能力,但涉及数据上传与隐私考量;本地化模式则侧重轻量级集成,通过IDE插件实现快速代码补全,强调响应速度与数据安全。近期行业热议的Claude面部识别认证事件与Co

weixin_33908217的博客 429

2026年数学建模国赛论文排版规范:Word与LaTeX终极对比及模板

提前演练:不要等到比赛开始才第一次使用排版工具。至少在赛前一个月完成1-2篇模拟论文的全流程排版练习。建立检查清单:基于国赛规范制定排版检查清单,在提交前逐项核对——公式编号连续?图表引用准确?参考文献完整?页数不超限?善用模板但不止于模板:模板提供的是起点而非终点。根据自身需求调整宏包配置和样式参数,理解每一行配置的含义。关注评审体验:从评委的视角审视论文——重点内容是否突出?逻辑结构是否清晰?视觉层次是否合理?备份与容错:无论使用何种工具,建立多级备份机制。本地、云端、U盘各存一份,且定期保存历史版本。

YOLO 211

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

计算机学习思维:从抽象分层到自动化效率的四大核心模型

计算机学习思维是一种理解、拆解和构建复杂系统的元认知能力,它超越了具体语法和命令的掌握。其核心原理在于通过抽象分层来管理复杂性,利用分解与模式识别来破解难题,并依靠严谨逻辑与机器对话,最终通过自动化思维提升工程效率。这种思维模型的技术价值在于它能帮助开发者从被动解决问题转向主动设计系统,显著提升问题定位的精准度和解决方案的可持续性。在应用场景上,无论是调试网络故障、设计高并发架构,还是构建CI/CD流水线,都需要综合运用这些思维模型。本文深入探讨了抽象分层、分解与模式识别、严谨逻辑以及自动化效率这四大核心思

weixin_34267123的博客 408

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

从QCon到AICon:技术大会价值变迁与策略型参会指南

技术大会是软件工程师和架构师获取前沿知识、拓展视野的重要途径。其核心价值在于提供了一个高效的技术雷达和高质量的人脉连接器,帮助从业者验证自身技术判断。从软件工程基石到人工智能范式转移,技术大会的议题演进反映了行业重心的迁移。例如,QCon大会长期聚焦于微服务、容器化、DevOps、架构演进与高可用性等经典软件工程课题,强调深度与实践性。而AICon的崛起则标志着以大模型、Agent、RAG为代表的人工智能技术从点缀变为核心,技术栈发生了颠覆性变化,涵盖了从模型层、编排层到运维层的新体系。对于参会者而言,策略

weixin_30279671的博客 393

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

AI编程助手实战:效率提升背后的质量折扣与技能重塑

代码生成与自动化编程是当前软件开发领域的热点技术,其核心原理是基于大规模代码库训练的大语言模型,能够根据上下文和自然语言描述自动补全或生成代码片段。这项技术的核心价值在于将开发者从重复性、模式化的编码劳动中解放出来,显著提升基础编码环节的效率。在实际工程实践中,它主要应用于快速生成样板代码、辅助代码补全、解释复杂逻辑以及重构建议等场景。然而,效率提升并非没有代价,开发者需要正视其带来的“质量折扣”,即AI生成的代码在边界处理、性能安全及架构一致性上可能存在隐患,这要求开发者的核心技能从编码能力向精准的需求澄

weixin_34246551的博客 289

嵌入式开发核心:从计算机体系结构到软硬件协同的系统化思维

计算机体系结构是理解计算设备如何工作的基石,它描述了CPU、内存、总线和外设如何协同完成指令执行与数据存取。其核心原理在于通过精密的硬件逻辑与软件指令控制,实现确定性的信息处理。这一基础对于嵌入式开发具有极高的技术价值,因为它直接决定了在资源受限环境下如何进行高效的软硬件协同设计。在嵌入式系统、物联网设备、工业控制等应用场景中,开发者必须在有限的处理器性能、内存和功耗约束下,确保系统的实时性与可靠性。这要求深入掌握C语言指针、内存操作及外设寄存器直接控制等底层技能,并构建从微控制器核心外设到实时操作系统、通

weixin_34280237的博客 512

TI Davinci/OMAP平台HDVPSS寄存器深度解析:VPDMA与HD_VENC_D实战配置

在嵌入式视频处理系统中,直接操作硬件寄存器是优化性能、实现定制化功能的关键技术。其核心原理在于通过精准配置DMA控制器与视频编码器的底层寄存器,实现对视频数据流、时序与色彩空间的精细控制。这项技术的核心价值在于能够突破标准驱动库的限制,解决流水线延迟、硬件级异常等深层问题,从而在视频采集、编码、显示等应用场景中实现极致性能与高可靠性。本文聚焦于德州仪器(TI)高性能SoC平台,深入剖析HDVPSS(高清视频处理子系统)中VPDMA(Video Port DMA)的客户端状态寄存器与HD_VENC_D(高清视

cunfuxiao7305的博客 716
上一篇: 这可能是ViewPager2滑动冲突最全面的处理方案
下一篇: 资深架构师和你谈谈 Kotlin 的泛型
懂你的大海
博客等级 码龄6年 9049粉丝 1381原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值