Android BatteryManager的使用及BatteryService源码分析

news/2024/5/19 23:33:10/文章来源:https://blog.csdn.net/weixin_44021334/article/details/132446113

当需要监控系统电量时,用 BatteryManager 来实现。

参考官网 监控电池电量和充电状态

获取电池信息

通过监听 Intent.ACTION_BATTERY_CHANGED 广播实现,在广播接收器中获取电池信息。

这是个粘性广播,即使过了广播发出的时间点后再注册广播接收器,也可以收到上一个广播消息。

按照我的 Demo ,没有触发电量变化,直接打开这个页面就可以收到广播。

public class BatteryActivity extends AppCompatActivity {private final static String TAG = BatteryActivity.class.getSimpleName();private BatteryReceiver receiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_battery);Objects.requireNonNull(getSupportActionBar()).setTitle(TAG);receiver = new BatteryReceiver();IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_BATTERY_CHANGED);registerReceiver(receiver, filter);}@Overrideprotected void onStop() {super.onStop();unregisterReceiver(receiver);}private static class BatteryReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);int temperature =  intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);int status  = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 0);int health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH, 0);int pluggen = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);}}}
}

电量

电量百分比 = 当前电量 / 电池总量

int level =  intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
int batteryPct = level * 100 / scale;

电池温度

模拟器获取的值是 250

int temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);

电池健康

int health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH, 0);

使用模拟器测试,
在这里插入图片描述
得到

电池健康
Unknown1
Good2
Overheat3
Dead4
Overvoltage5
Failed6

看 BatteryManager 源码,

	import android.hardware.health.V1_0.Constants;// values for "health" field in the ACTION_BATTERY_CHANGED Intentpublic static final int BATTERY_HEALTH_UNKNOWN = Constants.BATTERY_HEALTH_UNKNOWN; //1public static final int BATTERY_HEALTH_GOOD = Constants.BATTERY_HEALTH_GOOD; //2public static final int BATTERY_HEALTH_OVERHEAT = Constants.BATTERY_HEALTH_OVERHEAT; //3public static final int BATTERY_HEALTH_DEAD = Constants.BATTERY_HEALTH_DEAD; //4public static final int BATTERY_HEALTH_OVER_VOLTAGE = Constants.BATTERY_HEALTH_OVER_VOLTAGE; // 5public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = Constants.BATTERY_HEALTH_UNSPECIFIED_FAILURE; //6public static final int BATTERY_HEALTH_COLD = Constants.BATTERY_HEALTH_COLD; // 7

追踪到 frameworks/native/services/batteryservice/include/batteryservice/BatteryServiceConstants.h

enum {BATTERY_STATUS_UNKNOWN = 1,BATTERY_STATUS_CHARGING = 2,BATTERY_STATUS_DISCHARGING = 3,BATTERY_STATUS_NOT_CHARGING = 4,BATTERY_STATUS_FULL = 5,
};enum {BATTERY_HEALTH_UNKNOWN = 1,BATTERY_HEALTH_GOOD = 2,BATTERY_HEALTH_OVERHEAT = 3,BATTERY_HEALTH_DEAD = 4,BATTERY_HEALTH_OVER_VOLTAGE = 5,BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6,BATTERY_HEALTH_COLD = 7,
};

电池状态 & 充电类型

电池状态

判断是否在充电,

int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 0);

看 BatteryManager 源码,

	// values for "status" field in the ACTION_BATTERY_CHANGED Intentpublic static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;//1public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;//2public static final int BATTERY_STATUS_DISCHARGING = Constants.BATTERY_STATUS_DISCHARGING;//3public static final int BATTERY_STATUS_NOT_CHARGING = Constants.BATTERY_STATUS_NOT_CHARGING;//4public static final int BATTERY_STATUS_FULL = Constants.BATTERY_STATUS_FULL;//5

充电类型

判断充电类型, 交流电、USB充电、无线充电。

int pluggen = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);

模拟器测试,None = 0 ,AC charger = 1 。

看 BatteryManager 源码,

	// values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.// These must be powers of 2./** Power source is an AC charger. */public static final int BATTERY_PLUGGED_AC = OsProtoEnums.BATTERY_PLUGGED_AC; // = 1/** Power source is a USB port. */public static final int BATTERY_PLUGGED_USB = OsProtoEnums.BATTERY_PLUGGED_USB; // = 2/** Power source is wireless. */public static final int BATTERY_PLUGGED_WIRELESS = OsProtoEnums.BATTERY_PLUGGED_WIRELESS; // = 4

监听低电量

当电池点亮过低、电池电量充足会发出这两个广播。

按照官方建议,在电量低时应停用所有后台更新,此时应用应尽量避免进行后台操作。

	/*** Broadcast Action:  Indicates low battery condition on the device.* This broadcast corresponds to the "Low battery warning" system dialog.** <p class="note">This is a protected intent that can only be sent* by the system.*/@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";/*** Broadcast Action:  Indicates the battery is now okay after being low.* This will be sent after {@link #ACTION_BATTERY_LOW} once the battery has* gone back up to an okay state.** <p class="note">This is a protected intent that can only be sent* by the system.*/@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";

按照官网静态广播的写法,没有接收到 ,

		<receiverandroid:name=".battery.BatteryReceiver"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.intent.action.BATTERY_LOW"/><action android:name="android.intent.action.BATTERY_OKAY"/></intent-filter></receiver>

用动态广播的写法可以接收到,

receiver = new BatteryReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_BATTERY_OKAY);
registerReceiver(receiver, filter);

用模拟器测试 ,
电量 15% 触发 Intent.ACTION_BATTERY_LOW ,电量 20% 触发 Intent.ACTION_BATTERY_OKAY

BatteryService源码分析

基于安卓11。

源码在 frameworks/base/services/core/java/com/android/server/BatteryService.java

对应的阈值都是定义在 frameworks$/base/core/res/res/values/config.xml , 厂商如需定制就改这里。

初始化

BatteryService 继承 SystemService ,

构造函数中

  • 初始化 Handler ;
  • 通过 LightsManager 实例化 Led ;
  • 获取各个阈值;
  • 监测 invalid_charger 。

onStart() 中

  • 注册电池健康回调,收到回调消息会调用 update(android.hardware.health.V2_1.HealthInfo info) 方法更新电池信息;
  • 初始化 BatteryPropertiesRegistrar 、BinderService 、LocalService。

onBootPhase(int phase) 中

  • 监听 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL 的变化,有变化时调用 updateBatteryWarningLevelLocked() 方法更新一次电池信息。
  • 调用 updateBatteryWarningLevelLocked() 方法更新一次电池信息。
public final class BatteryService extends SystemService {//...public BatteryService(Context context) {super(context);mContext = context;mHandler = new Handler(true /*async*/);mLed = new Led(context, getLocalService(LightsManager.class));mBatteryStats = BatteryStatsService.getService();mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);mCriticalBatteryLevel = mContext.getResources().getInteger(com.android.internal.R.integer.config_criticalBatteryWarningLevel);mLowBatteryWarningLevel = mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryCloseWarningBump);mShutdownBatteryTemperature = mContext.getResources().getInteger(com.android.internal.R.integer.config_shutdownBatteryTemperature);mBatteryLevelsEventQueue = new ArrayDeque<>();mMetricsLogger = new MetricsLogger();// watch for invalid charger messages if the invalid_charger switch existsif (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {UEventObserver invalidChargerObserver = new UEventObserver() {@Overridepublic void onUEvent(UEvent event) {final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;synchronized (mLock) {if (mInvalidCharger != invalidCharger) {mInvalidCharger = invalidCharger;}}}};invalidChargerObserver.startObserving("DEVPATH=/devices/virtual/switch/invalid_charger");}}//...@Overridepublic void onStart() {registerHealthCallback();mBinderService = new BinderService();publishBinderService("battery", mBinderService);mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);publishLocalService(BatteryManagerInternal.class, new LocalService());}@Overridepublic void onBootPhase(int phase) {if (phase == PHASE_ACTIVITY_MANAGER_READY) {// check our power situation now that it is safe to display the shutdown dialog.synchronized (mLock) {ContentObserver obs = new ContentObserver(mHandler) {@Overridepublic void onChange(boolean selfChange) {synchronized (mLock) {updateBatteryWarningLevelLocked();}}};final ContentResolver resolver = mContext.getContentResolver();resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),false, obs, UserHandle.USER_ALL);updateBatteryWarningLevelLocked();}}}//...private void updateBatteryWarningLevelLocked() {final ContentResolver resolver = mContext.getContentResolver();int defWarnLevel = mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);mLowBatteryWarningLevel = Settings.Global.getInt(resolver,Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);if (mLowBatteryWarningLevel == 0) {mLowBatteryWarningLevel = defWarnLevel;}if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {mLowBatteryWarningLevel = mCriticalBatteryLevel;}mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryCloseWarningBump);processValuesLocked(true);}private void processValuesLocked(boolean force) {//...shutdownIfNoPowerLocked();shutdownIfOverTempLocked();// ...if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||mHealthInfo.batteryHealth != mLastBatteryHealth ||mHealthInfo.batteryPresent != mLastBatteryPresent ||mHealthInfo.batteryLevel != mLastBatteryLevel ||mPlugType != mLastPlugType ||mHealthInfo.batteryVoltage != mLastBatteryVoltage ||mHealthInfo.batteryTemperature != mLastBatteryTemperature ||mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||mHealthInfo.batteryChargeCounter != mLastChargeCounter ||mInvalidCharger != mLastInvalidCharger)) {// ...mLastBatteryStatus = mHealthInfo.batteryStatus;mLastBatteryHealth = mHealthInfo.batteryHealth;mLastBatteryPresent = mHealthInfo.batteryPresent;mLastBatteryLevel = mHealthInfo.batteryLevel;mLastPlugType = mPlugType;mLastBatteryVoltage = mHealthInfo.batteryVoltage;mLastBatteryTemperature = mHealthInfo.batteryTemperature;mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;mLastChargeCounter = mHealthInfo.batteryChargeCounter;mLastBatteryLevelCritical = mBatteryLevelCritical;mLastInvalidCharger = mInvalidCharger;}}
}

低电量广播

电量 15% 触发 Intent.ACTION_BATTERY_LOW ,电量 20% 触发 Intent.ACTION_BATTERY_OKAY

<integer name="config_lowBatteryWarningLevel">15</integer>
<integer name="config_lowBatteryCloseWarningBump">5</integer>

逻辑很清楚,

当电量低于 mLowBatteryWarningLevel 就发出广播 Intent.ACTION_BATTERY_LOW

当电量高于 mLowBatteryCloseWarningLevel 就发出广播 Intent.ACTION_BATTERY_OKAY

	private int mLowBatteryWarningLevel;private int mLowBatteryCloseWarningLevel;// ...public BatteryService(Context context) {// ...mLowBatteryWarningLevel = mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(com.android.internal.R.integer.config_lowBatteryCloseWarningBump);// ...}// ...if (shouldSendBatteryLowLocked()) {mSentLowBatteryBroadcast = true;final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});} else if (mSentLowBatteryBroadcast &&mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {mSentLowBatteryBroadcast = false;final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});}// ...private boolean shouldSendBatteryLowLocked() {final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;/* The ACTION_BATTERY_LOW broadcast is sent in these situations:* - is just un-plugged (previously was plugged) and battery level is*   less than or equal to WARNING, or* - is not plugged and battery level falls to WARNING boundary*   (becomes <= mLowBatteryWarningLevel).*/return !plugged&& mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN&& mHealthInfo.batteryLevel <= mLowBatteryWarningLevel&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);}

超低电量关机

BatteryService.java 里,

	//...shutdownIfNoPowerLocked();// ...private boolean shouldShutdownLocked() {if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {return (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL);}if (mHealthInfo.batteryLevel > 0) {return false;}// Battery-less devices should not shutdown.if (!mHealthInfo.batteryPresent) {return false;}// If battery state is not CHARGING, shutdown.// - If battery present and state == unknown, this is an unexpected error state.// - If level <= 0 and state == full, this is also an unexpected state// - All other states (NOT_CHARGING, DISCHARGING) means it is not charging.return mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_CHARGING;}private void shutdownIfNoPowerLocked() {// shut down gracefully if our battery is critically low and we are not powered.// wait until the system has booted before attempting to display the shutdown dialog.if (shouldShutdownLocked()) {mHandler.post(new Runnable() {@Overridepublic void run() {if (mActivityManagerInternal.isSystemReady()) {Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);intent.putExtra(Intent.EXTRA_REASON,PowerManager.SHUTDOWN_LOW_BATTERY);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivityAsUser(intent, UserHandle.CURRENT);}}});}}

电量过低时发出 Intent.ACTION_REQUEST_SHUTDOWN 广播,

frameworks/base/core/java/com/android/internal/app/ShutdownActivity.java 处理广播

frameworks/base/core/res/AndroidManifest.xml

	<activity android:name="com.android.internal.app.ShutdownActivity"android:permission="android.permission.SHUTDOWN"android:theme="@style/Theme.NoDisplay"android:excludeFromRecents="true"><intent-filter><action android:name="com.android.internal.intent.action.REQUEST_SHUTDOWN" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><intent-filter><action android:name="android.intent.action.REBOOT" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity>

frameworks/base/core/java/com/android/internal/app/ShutdownActivity.java

public class ShutdownActivity extends Activity {private static final String TAG = "ShutdownActivity";private boolean mReboot;private boolean mConfirm;private boolean mUserRequested;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Intent intent = getIntent();mReboot = Intent.ACTION_REBOOT.equals(intent.getAction());mConfirm = intent.getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);mUserRequested = intent.getBooleanExtra(Intent.EXTRA_USER_REQUESTED_SHUTDOWN, false);final String reason = mUserRequested? PowerManager.SHUTDOWN_USER_REQUESTED: intent.getStringExtra(Intent.EXTRA_REASON);Slog.i(TAG, "onCreate(): confirm=" + mConfirm);Thread thr = new Thread("ShutdownActivity") {@Overridepublic void run() {IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));try {if (mReboot) {pm.reboot(mConfirm, null, false);} else {pm.shutdown(mConfirm, reason, false);}} catch (RemoteException e) {}}};thr.start();finish();// Wait for us to tell the power manager to shutdown.try {thr.join();} catch (InterruptedException e) {}}
}

高温关机

<integer name="config_shutdownBatteryTemperature">680</integer>

超出这个定义的温度就关机,前文模拟器中获取的温度是 250 ,还是很安全的。

		private int mShutdownBatteryTemperature;//...public BatteryService(Context context) {// ...mShutdownBatteryTemperature = mContext.getResources().getInteger(com.android.internal.R.integer.config_shutdownBatteryTemperature);// ...}// ...shutdownIfOverTempLocked();// ...private void shutdownIfOverTempLocked() {// shut down gracefully if temperature is too high (> 68.0C by default)// wait until the system has booted before attempting to display the// shutdown dialog.if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) {mHandler.post(new Runnable() {@Overridepublic void run() {if (mActivityManagerInternal.isSystemReady()) {Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);intent.putExtra(Intent.EXTRA_REASON,PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivityAsUser(intent, UserHandle.CURRENT);}}});}}

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

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

相关文章

星戈瑞分析FITC-PEG-Alkyne的荧光特性和光谱特性

​欢迎来到星戈瑞荧光stargraydye&#xff01;小编带您盘点&#xff1a; FITC-PEG-Alkyne的荧光特性和光谱特性是对其荧光性能进行分析的方面。以下是FITC-PEG-Alkyne的一些常见荧光特性和光谱特性&#xff1a; **1. 荧光激发波长&#xff1a;**FITC-PEG-Alkyne的荧光激发波长通…

面试热题(不同的二分搜索树)

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 经典的面试题&#xff0c;这部分涉及了组合数学中的卡特兰数&#xff0c;如果对其不清楚的同学可以去看我以前的博客卡特兰数 …

vue项目中使用ts的枚举类型

vue项目中要使用ts的枚举类型需要为script标签的lang属性添加ts属性值 <script lang"ts" setup> </script > 声明枚举类型&#xff1a; //语法 /* enum 枚举名称 {可能的值 }*/ enum scenic_status {"正常" 1,"审核中","暂停…

[CVPR 2023]PyramidFlow-训练并推理-附bug调试

CVPR2023-PyramidFlow-zero shot异常检测网络 代码调试记录 一.论文以及开源代码二.前期代码准备三.环境配置四.bug调试num_samples should be a positive integer value, but got num_samples0AttributeError: Cant pickle local object fix_randseed.<locals>.seed_wor…

恒运资本:抄底单是什么意思?

抄底单是指出资者在股票或其他金融产品跌幅较大时&#xff0c;以较低价格买入的清单。其目的是在商场低迷、经济不景气时通过较低买入价格获取更多的财物&#xff0c;等待商场反弹时出售&#xff0c;然后取得高额收益。一般来说&#xff0c;需求具有必定的专业常识和危险意识的…

vite创建项目命令

1.第一步运行创建命令&#xff08;npm&#xff09; npm create vitelatest也可以使用yarn yarn create vite还可以 pnpm create vite注意的地方&#xff1a;首次创建的时候会出现这个 Need to install the following packages:create-vitelatest Ok to proceed? (y) 直接y就…

C++入门:引用是什么

目录 1.引用的概念 2.引用的特征 3.常引用 4.引用使用场景 5.传值&#xff0c;传引用效率比较 6.引用与指针的区别 1.引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用…

HDLBits-Verilog学习记录 | Verilog Language-Basics(2)

文章目录 9.Declaring wires | wire decl10. 7458 chip 9.Declaring wires | wire decl problem:Implement the following circuit. Create two intermediate wires (named anything you want) to connect the AND and OR gates together. Note that the wire that feeds the …

设计模式(11)观察者模式

一、概述&#xff1a; 1、定义&#xff1a;观察者模式定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象&#xff0c;使它们能够自动更新自己。 2、结构图&#xff1a; public interface S…

【PHP】文件包含-includerequire

文章目录 文件包含意义&#xff1a;四种形式文件加载原理include和require的区别文件的加载路径文件嵌套包含 文件包含 文件包含&#xff1a;在一个PHP脚本中&#xff0c;去将另外一个文件&#xff08;PHP&#xff09;包含进来&#xff0c;去合作完成一件事情。 意义&#xf…

【SpringSecurity】二、密码处理与获取当前登录用户

文章目录 一、密码处理1、加密方案2、BCryptPasswordEncoder类初体验3、使用加密码加密 二、获取当前登录用户1、方式一&#xff1a;通过安全上下文的静态调用2、方式二&#xff1a;做为Controller中方法的参数3、方式三&#xff1a;从HTTPServletRequest中获取4、方式四&#…

统计Mysql库中每个表的总行数,解决table_rows不准确问题

1、拼接SQL selectsubstring( GROUP_CONCAT(a.sf SEPARATOR ),1,length(GROUP_CONCAT(a.sf SEPARATOR ))-10) as sql_str from( select concat(select ", TABLE_name , ", count(*) as row_num from , TABLE_SCHEMA, .,TABLE_name, union all ) as sf frominformat…

js实现定时器

用原生js实现一个倒计时效果.最下面有全部源码,需要自取 js语法: setTimeout:定时器 document.getElementById:Document的方法 getElementById()返回一个匹配特定 ID的元素。由于元素的 ID 在大部分情况下要求是独一无二的&#xff0c;这个方法自然而然地成为了一个高效查找特…

STL---vector

目录 1.vector的介绍及使用 2.vector接口说明及模拟实现 2.1vector定义 2.2vector迭代器的使用 2.3vector容量 2.4vector增删查改 3迭代器失效 4.使用memcpy拷贝 5.模拟实现 1.vector的介绍及使用 vector的文档介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数…

不修改原图片,自动添加水印

只要添加我写的一个DynaWatermark2.1.1.jar的包,然后在web.xml里配置一下,哪个文件夹下的图片需要动态水印,就可以啦!以后通过页面访问这个文件夹下的图片,就会自动加上水印.但不会修改文件夹里图片本身.   这个jar里面有添加图片水印和文字水印两个servlet.(不能两个都配置,…

科技新秀巅峰决战,百度商业AI技术创新大赛圆满收官

2023年&#xff0c;生成式AI在全球范围内的热议引爆了AIGC前沿技术快速迭代。人工智能从辨别式AI走向生成式AI的方向性改变&#xff0c;进一步革新了社会生产力&#xff0c;各行各业的生产模式发生了翻天覆地的变化。 值此关键变革之际&#xff0c;作为国内人工智能领域的佼佼…

蓝蓝设计-UI设计公司案例-HMI列车监控系统界面设计解决方案

2013年&#xff0c;为加拿大庞巴迪(Bombardier)设计列车监控系统界面设计。 2015-至今&#xff0c;为中车集团旗下若干公司提供HMI列车监控系统界面设计,综合考虑中车特点、城轨车、动车组的不同需求以及HMI硬键屏和触摸 屏的不同操作方式&#xff0c;重构框架设计、交互设计、…

2022美亚杯个人赛复刻

案件详情 于2022年10月&#xff0c;有市民因接获伪冒快递公司的电邮&#xff0c;不慎地于匪徒架设的假网站提供了个人信用咭资料导致经济损失。 警方追查下发现当中一名受骗市民男子李大輝 (TaiFai) 的信用卡曾经被匪徒在区内的商舖购物。 后来警方根据IP地址&#xff0c;锁定…

考研408 | 【操作系统】 进程管理

进程的概念 进程的组成 进程的组成-PCB 进程的组成--程序段、数据段 程序如何运行 总结&#xff1a; 进程的特征 总结 进程的状态 进程的状态--创建态、就绪态 进程的状态--运行态 进程的状态--阻塞态 进程的状态--终止态 进程状态的转换 进程的组织 进程的组织--链接方式 进程…

【Python原创毕设|课设】基于Python Flask的上海美食信息与可视化宣传网站项目-文末附下载方式以及往届优秀论文,原创项目其他均为抄袭

基于Python Flask的上海美食信息与可视化宣传网站&#xff08;获取方式访问文末官网&#xff09; 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 随着大数据和人工智能技术的迅速发展&#xff0c;我们设…