Android BatteryManager的使用及BatteryService源码分析

news2025/1/2 3:44:33

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

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

获取电池信息

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

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

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

public class BatteryActivity extends AppCompatActivity {

    private final static String TAG = BatteryActivity.class.getSimpleName();
    private BatteryReceiver receiver;

    @Override
    protected 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);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(receiver);
    }

    private static class BatteryReceiver extends BroadcastReceiver{

        @Override
        public 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 Intent
    public static final int BATTERY_HEALTH_UNKNOWN = Constants.BATTERY_HEALTH_UNKNOWN; //1
    public static final int BATTERY_HEALTH_GOOD = Constants.BATTERY_HEALTH_GOOD; //2
    public static final int BATTERY_HEALTH_OVERHEAT = Constants.BATTERY_HEALTH_OVERHEAT; //3
    public static final int BATTERY_HEALTH_DEAD = Constants.BATTERY_HEALTH_DEAD; //4
    public static final int BATTERY_HEALTH_OVER_VOLTAGE = Constants.BATTERY_HEALTH_OVER_VOLTAGE; // 5
    public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = Constants.BATTERY_HEALTH_UNSPECIFIED_FAILURE; //6
    public 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 Intent
    public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN;//1
    public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING;//2
    public static final int BATTERY_STATUS_DISCHARGING = Constants.BATTERY_STATUS_DISCHARGING;//3
    public static final int BATTERY_STATUS_NOT_CHARGING = Constants.BATTERY_STATUS_NOT_CHARGING;//4
    public 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";

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

		<receiver
            android: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 exists
        if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
            UEventObserver invalidChargerObserver = new UEventObserver() {
                @Override
                public 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");
        }
    }
	//...
	@Override
    public void onStart() {
        registerHealthCallback();

        mBinderService = new BinderService();
        publishBinderService("battery", mBinderService);
        mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
        publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);
        publishLocalService(BatteryManagerInternal.class, new LocalService());
    }

    @Override
    public 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) {
                    @Override
                    public 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() {
                    @Override
                    public 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() {
                    @Override
                    public 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() {
                @Override
                public 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;

    @Override
    protected 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") {
            @Override
            public 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() {
                @Override
                public 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.coloradmin.cn/o/918425.html

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

相关文章

基于数据采集网关的工业锅炉远程监控运维系统

随着社会经济的不断发展&#xff0c;工业生产规模不断扩大&#xff0c;生产工艺也在不断创新&#xff0c;工业锅炉已经实现自动化控制&#xff0c;但管理模式仍存在缺陷&#xff0c;目前锅炉主要以人工巡检为主&#xff0c;这种方式费时费力且无法及时发现生产中的隐患&#xf…

javaScript:带你深入了解基本数据类型和引用类型

目录 一.前言 二.Ecmascript 规定的变量有两种 补充 1.基本数据类型&#xff08;重点掌握&#xff09; 基本数据类型的特点 2.引用数据类型 &#xff08;重点掌握&#xff09; 引用数据类型的特点 三.什么是栈&#xff1f;堆&#xff1f; 下面代码帮助了解 解释 官…

线性数据结构:数组与链表的探索与应用

文章目录 1. 数组&#xff1a;连续存储的有序元素集合1.1 创建和访问数组1.2 数组的搜索与排序 2. 链表&#xff1a;非连续存储的动态数据结构2.1 单链表与双链表2.2 链表的操作与应用 3. 数组与链表的比较与应用3.1 数组与链表的比较3.2 数组与链表的应用 4. 总结与展望 &…

Docker基本部署和相关操作

1.安装docker服务&#xff0c;配置镜像加速器 1、yum安装并且添加源信息 yum install yum-utils device-mapper-persistent-data lvm2 -y yum-config-manager --add-repo https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo2、修改一些配置信息 sed…

跨境电商系统开发:解锁海外财富,轻松实现财富自由

了解跨境电商系统开发的重要性 随着全球化和科技发展的进程&#xff0c;跨境电商已经成为一种崭新且热门的商业模式。跨境电商系统开发为企业提供了进军海外市场的机会&#xff0c;解锁了海外财富&#xff0c;帮助实现财富自由。 跨境电商系统的基本架构 跨境电商系统的基本架…

反腐力度空前,医药行业全面合规势在必行!

“公立医院改革、临床试验自查、医疗反腐、分级诊疗、药品集中采购、一致性评价、最严限抗、两票制等一系列政策卷起了医疗界阵阵反腐风暴。据报道&#xff0c;全国已有至少155家医院的院长和书记接受了调查。。。” 医药行业是与人们的生命和健康息息相关的重要领域&#xff…

一云多芯,智能化转型的下一个工程化挑战

进入2023年&#xff0c;产业数字化和智能化转型升级进入了大规模工程化落地阶段。根据中国信通院《中国数字经济发展研究报告&#xff08;2023&#xff09;》&#xff0c;数字经济已经占我国GDP比重达到41.5%&#xff0c;相当于第二产业占国民经济的比重。随着产业数字化和智能…

java Collection/Map选型

1.Collection接口 Collection接口实现了Iterator接口&#xff0c;所以Collection接口的实现类都可以用迭代器进行迭代。 Collection接口主要有两大重要的子接口List(列表)、Set(集合)。 List的主要特点是&#xff1a;有序、值可重复、支持索引访问。 Set的主要特点是&#xf…

【学习FreeRTOS】第16章——FreeRTOS事件标志组

1.事件标志组简介 事件标志位&#xff1a;用一个位&#xff0c;来表示事件是否发生 事件标志组是一组事件标志位的集合&#xff0c; 可以简单的理解事件标志组&#xff0c;就是一个整数。 事件标志组的特点&#xff1a; 它的每一个位表示一个事件&#xff08;高8位不算&…

spring练习32-删除用户操作

18-Spring练习-删除用户操作_哔哩哔哩_bilibili 106 1、删除操作怎么做&#xff0c;点击删除的时候&#xff0c;我要发请求&#xff0c;就是controller某个方法当中&#xff0c;要不要携带参数那&#xff0c;因为你点这个&#xff0c;那个&#xff0c;都不一眼 2、你点这个你…

低压风机单片机方案

低压风机通常由电机、转子、机壳、进气管、出气管、齿轮和减速机等组成。电机带动转子旋转&#xff0c;旋转的转子带动齿轮和减速机转动&#xff0c;进而形成空气被吸入转子内部&#xff0c;通过旋转而产生的离心力把气体压缩&#xff0c;并将气体排出。 低压风机方案的主控型…

【C++入门到精通】C++入门 —— 模版(template)

阅读导航 前言一、模版的概念二、函数模版1. 函数模板概念2. 函数模板定义格式3. 函数模板的原理4. 函数模版的实例化&#x1f6a9;隐式实例化&#x1f6a9;显式实例化 5. 函数模板的匹配原则 三、类模板1. 类模板的定义格式2. 类模板的实例化 四、非类型模板参数1. 概念2. 定义…

GPT4模型架构的泄漏与分析

迄今为止&#xff0c;GPT4 模型是突破性的模型&#xff0c;可以免费或通过其商业门户&#xff08;供公开测试版使用&#xff09;向公众提供。它为许多企业家激发了新的项目想法和用例&#xff0c;但对参数数量和模型的保密却扼杀了所有押注于第一个 1 万亿参数模型到 100 万亿参…

Docker是什么?详谈它的框架、使用场景、优势

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、什么是 Docker&#xff1f; 二、Docker 的架构 1、Docker客户端 2、Docker守护进程 3、Docker镜像 4、Docker容器 5、Docker…

锚定医学营养 健启星深耕不辍

在生命医学中&#xff0c;营养被称为维持患者生命的物质基础。医学营养&#xff0c;是结合了医学临床营养、营养素与疾病预防等方面&#xff0c;并根据患者的医疗记录、身体检查及心理情况&#xff0c;由医生及专业营养师给出配比完善的营养素&#xff0c;以此来增加患者身体的…

SSM框架的学习与应用(Spring + Spring MVC + MyBatis)-Java EE企业级应用开发学习记录(第三天)动态SQL

动态SQL—SSM框架的学习与应用(Spring Spring MVC MyBatis)-Java EE企业级应用开发学习记录&#xff08;第三天&#xff09;Mybatis的动态SQL操作 昨天我们深入学习了Mybatis的核心对象SqlSessionFactoryBuilder&#xff0c;掌握MyBatis核心配置文件以及元素的使用,也掌握My…

《Zookeeper》源码分析(十九)之 LearnerHandler

目录 LearnerCnxAcceptorrun() LearnerCnxAcceptorHandlerrun() LearnerHandlerrun()syncFollower()SNAP全量同步startSendingPackets() LearnerCnxAcceptor 在Leader.lead()方法中创建并启动LearnerCnxAcceptor线程&#xff0c;该线程主要是建立LearnerCnxAcceptorHandler并将…

介绍两个js补环境项目

1. v-jstools 这个项目是一个浏览器插件&#xff0c;用来补环境的话&#xff0c;是非常好的一个插件。项目地址是&#xff1a;GitHub - cilame/v_jstools: https://github.com/cilame/v_jstools 这里是我的配置 这个是使用后的效果 可以看到&#xff0c;里面调用的环境都被检…

【ARM AMBA AXI 入门 10 - AXI 总线 DATA信号与 STRB 信号之间的关系 】

文章目录 AXI STRB 信号 AXI STRB 信号 AXI总线是ARM公司设计的高性能处理器接口&#xff0c;其中STRB和DATA信号在AXI协议中有特殊的含义和关系。 DATA信号&#xff1a;在AXI中&#xff0c;DATA信号用于在读写操作中传输实际的数据。数据的大小可以根据AXI接口的位宽来变化&…

Redis(缓存预热,缓存雪崩,缓存击穿,缓存穿透)

目录 一、缓存预热 二、缓存雪崩 三、缓存击穿 四、缓存穿透 一、缓存预热 开过车的都知道&#xff0c;冬天的时候启动我们的小汽车之后不要直接驾驶&#xff0c;先让车子发动机预热一段时间再启动。缓存预热是一样的道理。 缓存预热就是系统启动前&#xff0c;提前将相关的…