当前位置: 首页 > news >正文

Android开机动画

Android开机动画

  • 1、BootLoader开机图片
  • 2、Kernel开机图片
  • 3、系统启动时(BootAnimation)动画
    • 3.1 bootanimation.zip位置
    • 3.2 bootanimation启动
    • 3.3 SurfaceFlinger启动bootanimation
    • 3.4 播放开机动画playAnimation
    • 3.6 开机动画退出检测
    • 3.7 简易时序图
  • 4、bootanimation.zip文件

android12-release
推荐 Android 12 开机动画代码与流程详解


在这里插入图片描述

1、BootLoader开机图片

一般使用rle格式图片;例如放在splash分区

adb reboot bootloader
fastboot flash splash splash.img
fastboot reboot

2、Kernel开机图片

记录 kernel/drivers/video/msm/msm_fb.c 也是读出根目录下的xx.rle,并显示为开机画面

3、系统启动时(BootAnimation)动画

使用BootAnimation程序显示开机画面,如需修改开机画面,不用修改代码,只需按格式要求做bootanimation.zip包,放在系统的/system/media目录中,或/oem/media/product/media等目录。

代码路径:frameworks/base/cmds/bootanimation

3.1 bootanimation.zip位置

frameworks/base/cmds/bootanimation/BootAnimation.cpp,例如bootanimation.zip
在这里插入图片描述

3.2 bootanimation启动

frameworks/base/cmds/bootanimation/Android.bp
frameworks/base/cmds/bootanimation/bootanim.rc
frameworks/base/cmds/bootanimation/bootanimation_main.cpp
frameworks/base/cmds/bootanimation/BootAnimation.cpp
frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

SurfaceFlinger进程名:bootanim
bin文件:/system/bin/bootanimation
对应启动入口:/frameworks/base/cmds/bootanimation/bootanimation_main.cpp

bootAnimationDisabled()检测系统属性(debug.sf.nobootanimation、ro.boot.quiescent、ro.bootanim.quiescent.enabled),noBootAnimation 是否启动开机动画。注意init进程在启动bootanimation服务是disable的,不会主动将应用程序bootanimation启动起来。启动bootanimation是从surfaceFlinger这边来启动的

frameworks/base/cmds/bootanimation/bootanimation_main.cpp

int main()
{setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);bool noBootAnimation = bootAnimationDisabled();ALOGI_IF(noBootAnimation,  "boot animation disabled");if (!noBootAnimation) {sp<ProcessState> proc(ProcessState::self());ProcessState::self()->startThreadPool();// create the boot animation object (may take up to 200ms for 2MB zip)sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());waitForSurfaceFlinger();boot->run("BootAnimation", PRIORITY_DISPLAY);ALOGV("Boot animation set up. Joining pool.");IPCThreadState::self()->joinThreadPool();}return 0;
}

frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

bool bootAnimationDisabled() {char value[PROPERTY_VALUE_MAX];property_get("debug.sf.nobootanimation", value, "0");if (atoi(value) > 0) {return true;}property_get("ro.boot.quiescent", value, "0");if (atoi(value) > 0) {// Only show the bootanimation for quiescent boots if this system property is set to enabledif (!property_get_bool("ro.bootanim.quiescent.enabled", false)) {return true;}}return false;
}

3.3 SurfaceFlinger启动bootanimation

SurfaceFlinger启动-Android12 初始化时候 mStartPropertySetThread->Start() 在线程中设置property_set("ctl.start", "bootanim")启动开机动画

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp

#include <cutils/properties.h>
#include "StartPropertySetThread.h"namespace android {StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}status_t StartPropertySetThread::Start() {return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
}bool StartPropertySetThread::threadLoop() {// Set property service.sf.present_timestamp, consumer need check its readinessproperty_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");// Clear BootAnimation exit flagproperty_set("service.bootanim.exit", "0");property_set("service.bootanim.progress", "0");// Start BootAnimation if not startedproperty_set("ctl.start", "bootanim");// Exit immediatelyreturn false;
}} // namespace android

3.4 播放开机动画playAnimation

  • result = android()android原生动画;result = movie()自动动画
  • playAnimation(*mAnimation)播放动画;releaseAnimation(mAnimation)释放动画资源
  • 播放动画过程:initTexture(frame.map, &w, &h)drawClock(animation.clockFont, part.clockPosX, part.clockPosY)drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY)checkExit()
  • checkExit()检测属性"service.bootanim.exit"退出动画
bool BootAnimation::threadLoop() {bool result;// We have no bootanimation file, so we use the stock android logo// animation.if (mZipFileName.isEmpty()) {result = android();} else {result = movie();}mCallbacks->shutdown();eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);eglDestroyContext(mDisplay, mContext);eglDestroySurface(mDisplay, mSurface);mFlingerSurface.clear();mFlingerSurfaceControl.clear();eglTerminate(mDisplay);eglReleaseThread();IPCThreadState::self()->stopProcess();return result;
}
bool BootAnimation::movie() {if (mAnimation == nullptr) {mAnimation = loadAnimation(mZipFileName);}if (mAnimation == nullptr)return false;// mCallbacks->init() may get called recursively,// this loop is needed to get the same resultsfor (const Animation::Part& part : mAnimation->parts) {if (part.animation != nullptr) {mCallbacks->init(part.animation->parts);}}mCallbacks->init(mAnimation->parts);bool anyPartHasClock = false;for (size_t i=0; i < mAnimation->parts.size(); i++) {if(validClock(mAnimation->parts[i])) {anyPartHasClock = true;break;}}if (!anyPartHasClock) {mClockEnabled = false;}// Check if npot textures are supportedmUseNpotTextures = false;String8 gl_extensions;const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));if (!exts) {glGetError();} else {gl_extensions.setTo(exts);if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||(gl_extensions.find("GL_OES_texture_npot") != -1)) {mUseNpotTextures = true;}}// Blend required to draw time on top of animation frames.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);glShadeModel(GL_FLAT);glDisable(GL_DITHER);glDisable(GL_SCISSOR_TEST);glDisable(GL_BLEND);glBindTexture(GL_TEXTURE_2D, 0);glEnable(GL_TEXTURE_2D);glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);bool clockFontInitialized = false;if (mClockEnabled) {clockFontInitialized =(initFont(&mAnimation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);mClockEnabled = clockFontInitialized;}initFont(&mAnimation->progressFont, PROGRESS_FONT_ASSET);if (mClockEnabled && !updateIsTimeAccurate()) {mTimeCheckThread = new TimeCheckThread(this);mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);}playAnimation(*mAnimation);if (mTimeCheckThread != nullptr) {mTimeCheckThread->requestExit();mTimeCheckThread = nullptr;}if (clockFontInitialized) {glDeleteTextures(1, &mAnimation->clockFont.texture.name);}releaseAnimation(mAnimation);mAnimation = nullptr;return false;
}
bool BootAnimation::playAnimation(const Animation& animation) {const size_t pcount = animation.parts.size();nsecs_t frameDuration = s2ns(1) / animation.fps;SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",elapsedRealtime());int fadedFramesCount = 0;int lastDisplayedProgress = 0;for (size_t i=0 ; i<pcount ; i++) {const Animation::Part& part(animation.parts[i]);const size_t fcount = part.frames.size();glBindTexture(GL_TEXTURE_2D, 0);// Handle animation packageif (part.animation != nullptr) {playAnimation(*part.animation);if (exitPending())break;continue; //to next part}// process the part not only while the count allows but also if already fadingfor (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) {if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;mCallbacks->playPart(i, part, r);glClearColor(part.backgroundColor[0],part.backgroundColor[1],part.backgroundColor[2],1.0f);// For the last animation, if we have progress indicator from// the system, display it.int currentProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);bool displayProgress = animation.progressEnabled &&(i == (pcount -1)) && currentProgress != 0;for (size_t j=0 ; j<fcount ; j++) {if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;processDisplayEvents();const int animationX = (mWidth - animation.width) / 2;const int animationY = (mHeight - animation.height) / 2;const Animation::Frame& frame(part.frames[j]);nsecs_t lastFrame = systemTime();if (r > 0) {glBindTexture(GL_TEXTURE_2D, frame.tid);} else {if (part.count != 1) {glGenTextures(1, &frame.tid);glBindTexture(GL_TEXTURE_2D, frame.tid);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}int w, h;initTexture(frame.map, &w, &h);}const int xc = animationX + frame.trimX;const int yc = animationY + frame.trimY;Region clearReg(Rect(mWidth, mHeight));clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));if (!clearReg.isEmpty()) {Region::const_iterator head(clearReg.begin());Region::const_iterator tail(clearReg.end());glEnable(GL_SCISSOR_TEST);while (head != tail) {const Rect& r2(*head++);glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());glClear(GL_COLOR_BUFFER_BIT);}glDisable(GL_SCISSOR_TEST);}// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)// which is equivalent to mHeight - (yc + frame.trimHeight)const int frameDrawY = mHeight - (yc + frame.trimHeight);glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);// if the part hasn't been stopped yet then continue fading if necessaryif (exitPending() && part.hasFadingPhase()) {fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,++fadedFramesCount);if (fadedFramesCount >= part.framesToFadeCount) {fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading}}if (mClockEnabled && mTimeIsAccurate && validClock(part)) {drawClock(animation.clockFont, part.clockPosX, part.clockPosY);}if (displayProgress) {int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);// In case the new progress jumped suddenly, still show an// increment of 1.if (lastDisplayedProgress != 100) {// Artificially sleep 1/10th a second to slow down the animation.usleep(100000);if (lastDisplayedProgress < newProgress) {lastDisplayedProgress++;}}// Put the progress percentage right below the animation.int posY = animation.height / 3;int posX = TEXT_CENTER_VALUE;drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY);}handleViewport(frameDuration);eglSwapBuffers(mDisplay, mSurface);nsecs_t now = systemTime();nsecs_t delay = frameDuration - (now - lastFrame);//SLOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));lastFrame = now;if (delay > 0) {struct timespec spec;spec.tv_sec  = (now + delay) / 1000000000;spec.tv_nsec = (now + delay) % 1000000000;int err;do {err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, nullptr);} while (err<0 && errno == EINTR);}checkExit();}usleep(part.pause * ns2us(frameDuration));if (exitPending() && !part.count && mCurrentInset >= mTargetInset &&!part.hasFadingPhase()) {if (lastDisplayedProgress != 0 && lastDisplayedProgress != 100) {android::base::SetProperty(PROGRESS_PROP_NAME, "100");continue;}break; // exit the infinite non-fading part when it has been played at least once}}}// Free textures created for looping parts now that the animation is done.for (const Animation::Part& part : animation.parts) {if (part.count != 1) {const size_t fcount = part.frames.size();for (size_t j = 0; j < fcount; j++) {const Animation::Frame& frame(part.frames[j]);glDeleteTextures(1, &frame.tid);}}}return true;
}

3.6 开机动画退出检测

  • checkExit()检测属性"service.bootanim.exit"退出动画;在playAnimation方法和android方法中都有一个checkExit方法来负责检查是否退出动画
  • WMS中performEnableScreen()设置SystemProperties.set("service.bootanim.exit", "1")
void BootAnimation::checkExit() {// Allow surface flinger to gracefully request shutdownchar value[PROPERTY_VALUE_MAX];property_get(EXIT_PROP_NAME, value, "0");int exitnow = atoi(value);if (exitnow) {requestExit();}
}

在这里插入图片描述

private void performEnableScreen() {synchronized (mGlobalLock) {ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: mDisplayEnabled=%b"+ " mForceDisplayEnabled=%b" + " mShowingBootMessages=%b"+ " mSystemBooted=%b mOnlyCore=%b. %s", mDisplayEnabled,mForceDisplayEnabled, mShowingBootMessages, mSystemBooted, mOnlyCore,new RuntimeException("here").fillInStackTrace());if (mDisplayEnabled) {return;}if (!mSystemBooted && !mShowingBootMessages) {return;}if (!mShowingBootMessages && !mPolicy.canDismissBootAnimation()) {return;}// Don't enable the screen until all existing windows have been drawn.if (!mForceDisplayEnabled) {if (mBootWaitForWindowsStartTime < 0) {// First time we will start waiting for all windows to be drawn.mBootWaitForWindowsStartTime = SystemClock.elapsedRealtime();}for (int i = mRoot.getChildCount() - 1; i >= 0; i--) {if (mRoot.getChildAt(i).shouldWaitForSystemDecorWindowsOnBoot()) {return;}}long waitTime = SystemClock.elapsedRealtime() - mBootWaitForWindowsStartTime;mBootWaitForWindowsStartTime = -1;if (waitTime > 10) {ProtoLog.i(WM_DEBUG_BOOT,"performEnableScreen: Waited %dms for all windows to be drawn",waitTime);}}if (!mBootAnimationStopped) {Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);// stop boot animation// formerly we would just kill the process, but we now ask it to exit so it// can choose where to stop the animation.SystemProperties.set("service.bootanim.exit", "1");mBootAnimationStopped = true;}if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: Waiting for anim complete");return;}try {IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");if (surfaceFlinger != null) {ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");Parcel data = Parcel.obtain();data.writeInterfaceToken("android.ui.ISurfaceComposer");surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHEDdata, null, 0);data.recycle();}} catch (RemoteException ex) {ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");}EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);mDisplayEnabled = true;ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");// Enable input dispatch.mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled);}try {mActivityManager.bootAnimationComplete();} catch (RemoteException e) {}mPolicy.enableScreenAfterBoot();// Make sure the last requested orientation has been applied.updateRotationUnchecked(false, false);
}

3.7 简易时序图

在这里插入图片描述

4、bootanimation.zip文件

bootanimation.zip
在这里插入图片描述 在这里插入图片描述
bootanimation.zip\desc.txt:

1080 2400 5
p 0 5 part0

bootanimation.zip\part0:
在这里插入图片描述

相关文章:

Android开机动画

Android开机动画 1、BootLoader开机图片2、Kernel开机图片3、系统启动时&#xff08;BootAnimation&#xff09;动画3.1 bootanimation.zip位置3.2 bootanimation启动3.3 SurfaceFlinger启动bootanimation3.4 播放开机动画playAnimation3.6 开机动画退出检测3.7 简易时序图 4、…...

vue中使用wow.js

一、安装 npm install wowjs --save-dev 二、main中引入 animate.css会自动安装 因为wow.js在animate.css基础上 main.js中引入animate.css import "animate.css" 三、 页面使用 有两种引入使用方式&#xff1a;1. import {WOW} from wowjs mounted() { n…...

网站edge -- 油猴 -> IDM

一、百度网盘限速 未解决 软件&#xff1a;IDM 安装路径&#xff1a; 1.1如果&#xff1a;edge 出问题打不开其他网站&#xff0c; 解决方法&#xff1a; 以管理员的身份&#xff0c;右击载这个软件&#xff0c;就好了 1.2使用这个软件 应该是右击这个软件 以管理员的身…...

Android片段

如果你希望应用根据不同的环境有不同的外观和行为&#xff0c;这种情况下就需要片段&#xff0c;片段是可以由不同活动重用的模块化代码组件。 片段&#xff08;Fragment&#xff09;是活动&#xff08;Activity&#xff09;的一种模块化部分&#xff0c;表示活动中的行为或界面…...

iOS实时监控与报警器

在现代信息化社会中&#xff0c;即使我们不在电脑前面也能随时获取到最新的数据。而苹果公司提供的iOS推送通知功能为我们带来了一种全新的方式——通过手机接收实时监控和报警信息。 首先让我们了解一下iOS推送通知。它是一个强大且灵活可定制化程度高、适用于各类应用场景&a…...

Git小白入门——上手实操之创建仓库和代码提交

版本库 什么是版本库呢&#xff1f;版本库又名仓库&#xff0c;英文名repository&#xff0c;简单理解成一个目录&#xff0c;目录里的所有文件都可以被Git管理&#xff0c;每个文件的修改、删除&#xff0c;Git都能跟踪&#xff0c;以便任何时刻都可以追踪历史&#xff0c;或…...

JS数组迭代方法实操

数组迭代方法有 1. every() 2.some() 3.foreach() 4.map() 5.filter 逐一操作&#xff0c;并简要区分之。 1 every() every() 方法使用指定的函数测试数组中所有的项&#xff0c;在数组的所有项都满足该条件时&#xff0c;才返回true&#xff0c;否则返回false&#xff1b; …...

基于snat+dnat发布内网K8S及Jenkins+gitlab+Harbor模拟CI/CD的综合项目

目录 项目名称 项目架构图 项目环境 项目概述 项目准备 项目步骤 一、修改每台主机的ip地址&#xff0c;同时设置永久关闭防火墙和selinux&#xff0c;修改好主机名&#xff0c;在firewalld服务器上开启路由功能并配置snat策略。 1. 在firewalld服务器上配置ip地址、设…...

时序预测 | MATLAB实现PSO-LSSVM粒子群算法优化最小二乘支持向量机时间序列预测未来

时序预测 | MATLAB实现PSO-LSSVM粒子群算法优化最小二乘支持向量机时间序列预测未来 目录 时序预测 | MATLAB实现PSO-LSSVM粒子群算法优化最小二乘支持向量机时间序列预测未来预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.Matlab实现PSO-LSSVM时间序列预测未…...

java IO流(二) 字符流 缓冲流 原始流与缓冲流性能分析

字符流 前面学习的字节流虽然可以读取文件中的字节数据&#xff0c;但是如果文件中有中文&#xff0c;使用字节流来读取&#xff0c;就有可能读到半个汉字的情况&#xff0c;这样会导致乱码。虽然使用读取全部字节的方法不会出现乱码&#xff0c;但是如果文件过大又不太合适。…...

复现XSS漏洞及分析

XSS漏洞概述&#xff1a; 类型一&#xff1a;反射型 类型二&#xff1a;存储型 类型三&#xff1a;DOM型 复现20字符短域名绕过 一、安装BEEF 1、在Kali中运行apt install beef-xss 2、运行beef 3、在浏览器访问 二、安装galleryCMS *遇到一点小问题 提示"last…...

Vue组件之间传值

聊一聊vue里面组件之间的传值 首先总结一下vue里面传值的几种关系&#xff1a; 如上图所示, A与B、A与C、B与D、C与F组件之间是父子关系&#xff1b; B与C之间是兄弟关系&#xff1b;A与D、A与E之间是隔代关系&#xff1b; D与F是堂兄关系&#xff0c;针对以上关系 我们把组件…...

windows查看端口占用,通过端口找进程号(查找进程号),通过进程号定位应用名(查找应用)(netstat、tasklist)

文章目录 通过端口号查看进程号netstat通过进程号定位应用程序tasklist 通过端口号查看进程号netstat 在Windows系统中&#xff0c;可以使用 netstat 命令来查看端口的占用情况。以下是具体的步骤&#xff1a; 打开命令提示符&#xff08;CMD&#xff09;&#xff1a;按WinR组…...

Weblogic SSRF【漏洞复现】

文章目录 漏洞测试注入HTTP头&#xff0c;利用Redis反弹shell redis不能启动问题解决 Path : vulhub/weblogic/ssrf 编译及启动测试环境 docker compose up -dWeblogic中存在一个SSRF漏洞&#xff0c;利用该漏洞可以发送任意HTTP请求&#xff0c;进而攻击内网中redis、fastcgi…...

文件读取漏洞复现(Metinfo 6.0.0)

文章目录 安装环境启动环境漏洞复现代码审计 安装环境 安装phpstudy&#xff0c;下载MetInfo 6.0.0版本软件&#xff0c;复制到phpstudy目录下的www目录中。 打开phpstudy&#xff0c;访问浏览器127.0.0.1/MetInfo6.0.0/install/index.php&#xff0c;打开Meinfo 6.0.0主页&a…...

【工程实践】使用git clone 批量下载huggingface模型文件

前言 经常需要下载模型到服务器&#xff0c;使用git clone方法可以快速实现模型下载。 1.选定要下载的模型 以下载moka-ai/m3e-base为例&#xff0c;切换到Files and versions。 2.更改下载网页的url 如上图所示&#xff0c;当前要下载模型网页的url为&#xff1a; https://hu…...

2020 杭电多校第三场 H Triangle Collision(反射套路 + 绕点旋转 + 矢量

2020 杭电多校第三场 H. Triangle Collision(反射套路 绕点旋转 矢量分解) 大意&#xff1a;给出一个等边三角形 &#xff0c; 以底边中线建立坐标系 &#xff0c; 给出三角形中一点 &#xff0c; 和其初始速度 &#xff0c; 小球在等边三角形中做完全弹性碰撞 &#xff0c; …...

Servlet属性、监听者和会话

没有servlet能单独存在。在当前的现代Web应用中&#xff0c;许多组件都是在一起协作共同完成一个目标。怎么让这些组件共享信息&#xff1f;如何隐藏信息&#xff1f;怎样让信息做到线程安全&#xff1f; 1 属性和监听者 1.1 初始化 容器初始化一个servlet时&#xff0c;会为…...

Gin学习记录2——路由

路由 一. 常规路由二. 动态路由三. 带参数的路由3.1 GET3.2 POST3.3 绑定 四. 简单的路由组五. 文件分组 一. 常规路由 package mainimport ("net/http""github.com/gin-gonic/gin" )func index(ctx *gin.Context) {ctx.String(http.StatusOK, "Hell…...

《计算机算法设计与分析》第一章:算法概述

第一章 算法概述 1.1 算法复杂性分析 公共标准&#xff1a;渐进时间复杂度 &#xff08;1&#xff09;大O表示法&#xff1a; 例如&#xff1a; 大O表示法和前面的最坏时间复杂度的区别在于&#xff1a;大O表示法表示的更为简洁&#xff0c; 而最坏时间复杂度相对就比较繁琐&am…...

分布式事务在跨境交易中的解决方案

随着全球化贸易与数字支付深度融合&#xff0c;跨境交易已从传统线下单证流转&#xff0c;转向多主体、跨区域、异构系统实时协同。一笔跨境订单通常涉及境内外电商平台、支付机构、收单行、清算网络、海关、物流与仓储等多个独立系统&#xff0c;数据分布在不同国家与地区&…...

保姆级教程:ANIMATEDIFF PRO电影级渲染工作站从零部署到实战

保姆级教程&#xff1a;ANIMATEDIFF PRO电影级渲染工作站从零部署到实战 1. 引言&#xff1a;从文字到电影&#xff0c;你的专属AI导演已就位 你有没有过这样的时刻&#xff1f;脑海里闪过一个绝美的画面——也许是未来都市的霓虹雨夜&#xff0c;也许是森林深处精灵起舞的瞬…...

零成本建站实战指南 — 从freehost免费主机到HTML页面部署

1. 为什么选择freehost免费主机&#xff1f; 对于刚接触网站搭建的新手来说&#xff0c;最大的障碍往往不是技术本身&#xff0c;而是前期投入成本。我见过太多人因为担心服务器费用而迟迟不敢动手实践&#xff0c;结果错过了最佳学习时机。freehost免费主机恰好解决了这个痛点…...

TIM+PWM输出+输入捕获测 频率+占空比(HAL库)

一&#xff1a;PWM输出&#xff08;TIM2_CH1&#xff09;HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);二&#xff1a;输入捕获测&#xff08;TIM1 CH1CH2&#xff09;三&#xff1a;开启CH1和CH2的中断四&#xff1a;初始化中断HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_1…...

2026毕业论文提速,文鉴智检工具深度分析

毕业季倒计时&#xff01;2026届毕业生最头疼的问题&#xff0c;莫过于毕业论文的“格式内耗”和“内容打磨”——明明内容达标&#xff0c;却被页眉页脚、参考文献格式反复打回&#xff1b;逐字逐句校对错别字、语法错误&#xff0c;耗时又易漏&#xff1b;好不容易改完格式&a…...

世嘉MD完全档案中文版PDF

核心内容分区MD 本体&#xff08;1988–1996&#xff09;&#xff1a;硬件迭代&#xff08;MD1/MD2/MD3&#xff09;、手柄、卡带&#xff1b;全游戏封面 截图 基础信息Mega-CD&#xff08;1991–1996&#xff09;、Super 32X&#xff08;1994–1995&#xff09;扩展外设与专…...

MangoHud与AI游戏助手:性能优化建议生成

MangoHud与AI游戏助手&#xff1a;性能优化建议生成 【免费下载链接】MangoHud A Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more. Discord: https://discordapp.com/invite/Gj5YmBb 项目地址: https://gitcode.com/gh_mirrors/ma/Mang…...

AI建站工具哪个好?2024最新选型标准与横向对比指南

面对市场上琳琅满目的AI建站工具&#xff0c;很多人都会入选择困难&#xff1a;到底哪个才是真智能&#xff1f;哪个最适合我这种零基础&#xff1f;哪个性价比最高&#xff1f;其实&#xff0c;与其盲目听信宣传&#xff0c;不如掌握一套通用的筛选标准&#xff0c;自己就能判…...

【无人售货柜・RK+YOLO】篇 6:安卓端落地!RK3576 + 安卓系统,YOLO RKNN 模型实时推理保姆级教程

目录 一、前置说明 & 新手扫盲 新手必守的红线 二、第一步&#xff1a;环境 & 资源准备&#xff0c;新手零坑版 三、第二步&#xff1a;创建安卓项目&#xff0c;配置环境 四、第三步&#xff1a;核心功能实现&#xff0c;全流程代码带注释 模块 1&#xff1a;动…...

车载嵌入式SDL显示驱动:轻量级确定性帧缓冲与硬件加速

1. 项目概述SDL&#xff08;Simple Display Library&#xff09;是专为大众汽车集团Cariad软件平台定制的轻量级嵌入式显示驱动抽象层&#xff0c;其设计目标并非通用图形库&#xff0c;而是面向车载TFT-LCD与GLCD&#xff08;Graphic LCD&#xff09;硬件的确定性、低延迟、高…...