Android之APP更新(通过接口更新)
文章目录
- 前言
- 一、效果图
- 二、实现步骤
- 1.AndroidManifest权限申请
- 2.activity实现
- 3.有版本更新弹框UpdateappUtilDialog
- 4.下载弹框DownloadAppUtils
- 5.弹框背景图
- 总结
前言
对于做Android的朋友来说,APP更新功能再常见不过了,因为平台更新审核时间较长,所以现在很多都会通过接口更新,这里就记录一下吧,欢迎各位讨论。
一、效果图
二、实现步骤
1.AndroidManifest权限申请
<!--外置存储卡写入权限--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!--请求安装APK的权限--><uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /><!--读取删除SD卡权限--><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!--修改删除SD卡权限--><uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"tools:ignore="ProtectedPermissions" /><uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />//application标签下加如下代码<!-- 安卓7.0安装时需要,拍照需要的临时权限 --><providerandroid:name="androidx.core.content.FileProvider"android:authorities="这里是applicationId也就是包名.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/provider_paths" /></provider>//这里的provider_paths文件放在xml文件下,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<paths><!--拍照需要的路径--><external-pathname="comxf.activity.provider.download"path="." /><external-files-path name="extfiles" path="autoupdatecache/" /><external-cache-path name="extcachs" path="autoupdatecache/" /><cache-path name="intcachs" path="autoupdatecache/" /><paths><external-path path="" name="download"/></paths></paths>
2.activity实现
1.通过接口获取Javabean对象
public Integer id;public String version_name;//App版本名public Integer version_code;//版本编号public String content;//版本更新内容public String is_must_update;//是否需要强更新(0:否,1:是)public String file_url;//app包的下载地址@Overridepublic String toString() {return "VersionUpgradeBean{" +"id=" + id +", version_name='" + version_name + '\'' +", version_code=" + version_code +", content='" + content + '\'' +", is_must_update='" + is_must_update + '\'' +", file_url='" + file_url + '\'' +'}';}
2.获取到版本号后判断是否高于当前版本
if (versionbean.version_code > MyApplication.getVersionCode(this@SetUpActivity)) {val myDialog = UpdateappUtilDialog()myDialog.initDialog(this@SetUpActivity, versionbean)myDialog.buttonClickEvent(object : UpdateappUtilDialog.DialogButtonClick {override fun cilckComfirmButton(view: View?) {myDialog.Dismiss()//6.0才用动态权限if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (ContextCompat.checkSelfPermission(this@SetUpActivity,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {// 申请读写内存卡内容的权限ActivityCompat.requestPermissions(this@SetUpActivity, arrayOf(Manifest.permission.`WRITE_EXTERNAL_STORAGE`), 123)} else {//授权成功if (FileUtils.createOrExistsDir(NetConst.baseFileName)) {val mUpdateManger = DownloadAppUtils(this@SetUpActivity, versionbean.file_url, versionbean)mUpdateManger.checkUpdateInfo()}}} else {//授权成功if (FileUtils.createOrExistsDir(NetConst.baseFileName)) {val mUpdateManger = DownloadAppUtils(this@SetUpActivity, versionbean.file_url, versionbean)mUpdateManger.checkUpdateInfo()}}}override fun cilckCancleButton(view: View?) {//点击取消按钮myDialog.Dismiss()}})}
3.用户权限结果处理
/*** todo 对用户权限授予结果处理** @param requestCode 权限要求码,即我们申请权限时传入的常量 如: TAKE_PHOTO_PERMISSION_REQUEST_CODE* @param permissions 保存权限名称的 String 数组,可以同时申请一个以上的权限* @param grantResults 每一个申请的权限的用户处理结果数组(是否授权)*/override fun onRequestPermissionsResult(requestCode: Int,permissions: Array<String?>,grantResults: IntArray) {super.onRequestPermissionsResult(requestCode, permissions, grantResults)when (requestCode) {123 -> {//授权成功if (FileUtils.createOrExistsDir(NetConst.baseFileName)) {val mUpdateManger = DownloadAppUtils(this@SetUpActivity, versionbean.file_url, versionbean)mUpdateManger.checkUpdateInfo()}}}}
3.有版本更新弹框UpdateappUtilDialog
1.util代码
/*** Created by :caoliulang* ❤* Creation time :2025/2/24* ❤* Function :更新app的Dialog*/
public class UpdateappUtilDialog {private TextView secondBtn, textvs;private ImageView tv_cancel;private AlertDialog alertDialog;private DialogButtonClick mClick;private TextView tv_desc;public interface DialogButtonClick {void cilckComfirmButton(View view);void cilckCancleButton(View view);}public void buttonClickEvent(DialogButtonClick bc) {if (bc != null) {mClick = bc;cilckEvent();}}public void initDialog(Context context, VersionUpgradeBean upbean) {alertDialog = new AlertDialog.Builder(context).create();alertDialog.show();alertDialog.setCancelable(false);//调用这个方法时,按对话框以外的地方不起作用。返回键 不作用
// alertDialog.setCanceledOnTouchOutside(false);//调用这个方法时,按对话框以外的地方不起作用。返回键 有作用Window window = alertDialog.getWindow();window.setContentView(R.layout.fragment_update_app);window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));tv_desc = window.findViewById(R.id.tv_desc);tv_desc.setText(upbean.content);secondBtn = window.findViewById(R.id.tv_ok);textvs = window.findViewById(R.id.textvs);textvs.setText(upbean.version_name);tv_cancel = window.findViewById(R.id.tv_cancel);//1不强制更新 2 强制更新
// if(upbean.getUpdateType().equals("2")){
// firstBtn.setVisibility(View.GONE);
// }// //不关闭弹窗也能点击外部事件
// alertDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);String isqg = upbean.is_must_update + "";if (isqg.equals("true")) {tv_cancel.setVisibility(View.GONE);} else {tv_cancel.setVisibility(View.VISIBLE);}}public void cilckEvent() {
// if (firstBtn != null) {
// firstBtn.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// alertDialog.dismiss();
// mClick.cilckCancleButton(v);
// }
// });secondBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {
// alertDialog.dismiss();mClick.cilckComfirmButton(v);}});tv_cancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mClick.cilckCancleButton(view);}});
// }}public void Dismiss() {if (null != alertDialog) {alertDialog.dismiss();}}}
2.xml布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#01000000"android:gravity="center"android:orientation="vertical"><RelativeLayoutandroid:layout_width="301dp"android:layout_height="400dp"android:orientation="vertical"><ImageViewandroid:id="@+id/iv_top"android:layout_width="match_parent"android:layout_height="match_parent"android:src="@mipmap/lib_update_app_top_bg" /><TextViewandroid:id="@+id/textname"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="16dp"android:layout_marginTop="55dp"android:text="@string/Newversionfound"android:textColor="#2e2e2e"android:textSize="18dp"android:textStyle="bold" /><TextViewandroid:id="@+id/textvs"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/textname"android:layout_marginLeft="16dp"android:layout_marginTop="5dp"android:text="1.0.0"android:textColor="#2e2e2e"android:textSize="16dp"android:textStyle="bold" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="210dp"android:layout_marginTop="180dp"android:orientation="vertical"><!--这个地方需要设置可以滚动--><ScrollViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:paddingTop="18dp"android:paddingBottom="5dp"android:scrollbars="none"><TextViewandroid:id="@+id/tv_desc"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:lineSpacingExtra="5dp"android:text="1.已知bug修复;\n2.新功能增加;\n3.性能优化;"android:textColor="@android:color/black"android:textSize="14dp" /></ScrollView><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="20dp"android:layout_marginBottom="20dp"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_ok"android:layout_width="match_parent"android:layout_height="44dp"android:background="@drawable/jianbianlanse"android:gravity="center"android:text="@string/UPDATENOW"android:textColor="#ffffff"android:textSize="18dp" /></LinearLayout></LinearLayout></RelativeLayout><ImageViewandroid:id="@+id/tv_cancel"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="15dp"android:src="@mipmap/ico_sjgb" /></LinearLayout>
4.下载弹框DownloadAppUtils
1.util代码如下
*** Created by :caoliulang* ❤* Creation time :2024/2/24* ❤* Function :APP更新下载*/
public class DownloadAppUtils {// 应用程序Contextpublic static Activity mContext;private static final String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "tdzr/Download/";// 保存apk的文件夹///storage/emulated/0/tdzr/Download/aidigital1.0.4.apkprivate static final String saveFileName = savePath + "aidigital" + MyApplication.versionname + ".apk";// 进度条与通知UI刷新的handler和msg常量private ProgressBar mProgress;private TextView text_progress, textvs;private static final int DOWN_UPDATE = 1;private static final int DOWN_OVER = 2;private static final int INT_NOT = 9;private String downlogdurl;//下载地址private int progress = 0;// 当前进度private Thread downLoadThread; // 下载线程private boolean interceptFlag = false;// 用户取消下载private AlertDialog dialog;private VersionUpgradeBean upbean;// 通知处理刷新界面的handler@SuppressLint("HandlerLeak")private Handler mHandler = new Handler() {@SuppressLint("HandlerLeak")@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case DOWN_UPDATE:mProgress.setProgress(progress); //设置第一进度text_progress.setText(progress + "%");break;case DOWN_OVER:
// //1不强制更新 2 强制更新
// if(upbean.getUpdateType().equals("1")){
// dialog.dismiss();
// }dialog.dismiss();installApk();break;case INT_NOT:dialog.dismiss();FileUtils.deleteFile(saveFileName);//删除文件ToastUtils.showToast(mContext.getResources().getString(R.string.Networkconnectionfailed));break;}super.handleMessage(msg);}};public DownloadAppUtils(Activity context, String downlogdurl, VersionUpgradeBean upbean) {this.mContext = context;this.downlogdurl = downlogdurl;this.upbean = upbean;System.out.println("过来了--1");}// 显示更新程序对话框,供主程序调用public void checkUpdateInfo() {//判断本地是否存在已下载的apk(有bug)
// if (FileUtils.isFileExists(saveFileName) == true) {
// //安装
// installApk();
// } else {
// //下载
// showDownloadDialog();
// }//判断本地是否存在已下载的apkif (FileUtils.isFileExists(saveFileName) == true) {//删除DeletFile.delete(savePath);}//下载showDownloadDialog();}//弹出更新进度条private void showDownloadDialog() {dialog = new AlertDialog.Builder(mContext).create();dialog.show();dialog.setCancelable(false);View viewt = View.inflate(mContext, R.layout.xiazai_two_dialog, null);Window window = dialog.getWindow();window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));dialog.setContentView(viewt);mProgress = viewt.findViewById(R.id.upprogressBar);text_progress = viewt.findViewById(R.id.text_progress);text_progress.setText("0%");textvs = viewt.findViewById(R.id.textvs);textvs.setText(upbean.version_name);ImageView tv_cancel = viewt.findViewById(R.id.tv_cancel);String isqg = upbean.is_must_update + "";if (isqg.equals("true")) {tv_cancel.setVisibility(View.GONE);} else {tv_cancel.setVisibility(View.VISIBLE);}tv_cancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {FileUtils.deleteFile(saveFileName);//删除文件dialog.dismiss();interceptFlag = true;}});downloadApk();}//安装apkprivate static void installApk() {File apkfile = new File(saveFileName);if (!apkfile.exists()) {return;}Intent intent = new Intent(Intent.ACTION_VIEW);//版本在7.0以上是不能直接通过uri访问的if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 由于没有在Activity环境下启动Activity,设置下面的标签intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致 参数3 共享的文件Uri apkUri = FileProvider.getUriForFile(mContext, "这里是applicationId也就是包名.fileprovider", apkfile);//添加这一句表示对目标应用临时授权该Uri所代表的文件intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.setDataAndType(apkUri, "application/vnd.android.package-archive");} else {intent.setDataAndType(Uri.fromFile(new File(saveFileName)),"application/vnd.android.package-archive");}mContext.startActivity(intent);}//下载apkprivate void downloadApk() {System.out.println("url打印:" + downlogdurl);downLoadThread = new Thread(mdownApkRunnable);downLoadThread.start();}private Runnable mdownApkRunnable = new Runnable() {@Overridepublic void run() {System.out.println("打印路径:" + saveFileName);URL url;try {url = new URL(downlogdurl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(15000); //设置连接超时为15sconn.setReadTimeout(15000); //读取数据超时也是15sint code = conn.getResponseCode();System.out.println("code打印:" + code);if (code == 200) {conn.connect();int length = conn.getContentLength();InputStream ins = conn.getInputStream();if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {Toast.makeText(mContext, "SD卡不可用~", Toast.LENGTH_SHORT).show();return;}File file = new File(savePath);if (!file.exists()) {file.mkdir();}String apkFile = saveFileName;File ApkFile = new File(apkFile);if (!ApkFile.exists()) {ApkFile.createNewFile();}FileOutputStream outStream = new FileOutputStream(ApkFile);int count = 0;byte buf[] = new byte[1024];do {int numread = ins.read(buf);count += numread;int s = (int) (((float) count / length) * 100);if (progress != s) {progress = (int) (((float) count / length) * 100);// 下载进度mHandler.sendEmptyMessage(DOWN_UPDATE);}if (numread <= 0) {// 下载完成通知安装mHandler.sendEmptyMessage(DOWN_OVER);break;}outStream.write(buf, 0, numread);} while (!interceptFlag);// 点击取消停止下载outStream.close();ins.close();} else {mHandler.sendEmptyMessage(INT_NOT);}} catch (Exception e) {//这里报错因为路径不对,正确路径storage/emulated/0/tdzr/Download/aidigital1.0.4.apkSystem.out.println("code打印:---" + e.toString());mHandler.sendEmptyMessage(INT_NOT);}}};
2.下载弹框xml布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#01000000"android:gravity="center"android:orientation="vertical"><RelativeLayoutandroid:layout_width="301dp"android:layout_height="400dp"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/topimg"android:layout_width="match_parent"android:layout_height="match_parent"android:src="@mipmap/lib_update_app_top_bg" /><TextViewandroid:id="@+id/textname"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="16dp"android:layout_marginTop="55dp"android:text="@string/Newversionfound"android:textColor="#2E2E2E"android:textSize="18dp"android:textStyle="bold" /><TextViewandroid:id="@+id/textvs"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@+id/textname"android:layout_marginLeft="16dp"android:layout_marginTop="5dp"android:text="1.0.0"android:textColor="#2E2E2E"android:textSize="16dp"android:textStyle="bold" /></RelativeLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="250dp"android:gravity="center_horizontal"android:orientation="vertical"><TextViewandroid:id="@+id/text_progress"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="0%"android:textColor="#2e2e2e"android:textSize="16dp"android:textStyle="bold" /><ProgressBarandroid:id="@+id/upprogressBar"style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"android:layout_width="match_parent"android:layout_height="18dp"android:layout_marginStart="15dp"android:layout_marginTop="15dp"android:layout_marginEnd="15dp"android:layout_marginBottom="15dp"android:max="100"android:progress="0"android:progressDrawable="@drawable/progressbar_h" /></LinearLayout></RelativeLayout><ImageViewandroid:id="@+id/tv_cancel"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="15dp"android:src="@mipmap/ico_sjgb" />
</LinearLayout>
3.progressbar_h(在drawable下新建文件)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@android:id/background"android:gravity="center_vertical|fill_horizontal"><shape android:shape="rectangle"><size android:height="20dp" /><solid android:color="#E4E4E4" /><corners android:radius="10dp" /></shape></item><!--第二进度条--><itemandroid:id="@android:id/secondaryProgress"android:gravity="center_vertical|fill_horizontal"><scale android:scaleWidth="100%"><shape android:shape="rectangle"><size android:height="20dp" /><solid android:color="#E4E4E4" /><corners android:radius="10dp" /></shape></scale></item><!--第一进度条--><itemandroid:id="@android:id/progress"android:gravity="center_vertical|fill_horizontal"><scale android:scaleWidth="100%"><shape android:shape="rectangle"><size android:height="20dp" /><solid android:color="#217FFD" /><corners android:radius="10dp" /></shape></scale></item></layer-list>
5.弹框背景图
总结
其实这功能挺简单的,就是里面细节太多,首先AndroidManifest加权限,还要加provider,provider里面记得更改包名,下载util里面的报名也是一样。其次判断版本是否更新,最后更新下载安装即可,得吃。
相关文章:

Android之APP更新(通过接口更新)
文章目录 前言一、效果图二、实现步骤1.AndroidManifest权限申请2.activity实现3.有版本更新弹框UpdateappUtilDialog4.下载弹框DownloadAppUtils5.弹框背景图 总结 前言 对于做Android的朋友来说,APP更新功能再常见不过了,因为平台更新审核时间较长&am…...
什么是 OCP 数据库专家
OCP 即 Oracle Certified Professional,Oracle 认证专业人员,代表持证人在 Oracle 数据库领域具备专业的技能和知识。获得 OCP 数据库专家认证意味着你在 Oracle 数据库管理、开发、优化等方面达到了较高的水平,能够独立承担复杂的数据库相关…...

基于AT89C51单片机的教室智能照明控制系统
点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/90419908?spm1001.2014.3001.5501 C16 部分参考设计如下: 摘 要 本项目的智能教室灯光控制系统通过合理的软硬件设计,有效地提升了教室…...
DIP的实际举例
SOLID原则。 依赖倒置原则(DIP)的核心是高层模块不应该依赖于低层模块,二者都应该依赖于抽象(接口或抽象类) 例如,随着业务的发展,订单总金额的计算规则可能需要根据不同的客户类型或促销活动…...

DeepSeek引领目标检测新趋势:如何通过知识蒸馏优化模型性能
目录 一、知识蒸馏是什么? 二、知识蒸馏在目标检测中的重要性 提升实时性 跨任务迁移学习 三、如何使用知识蒸馏优化目标检测? 训练教师模型 生成软标签 训练学生模型 调节温度参数 多教师蒸馏(可选) 四、案例分享 定…...
vue2.x 中父组件通过props向子组件传递数据详细解读
1. 父组件向子组件传递数据的步骤 在子组件中定义 props: 子组件通过 props 选项声明它期望接收的数据。props 可以是数组形式(简单声明)或对象形式(支持类型检查和默认值)。 在父组件中使用子组件时绑定 props&#x…...

安装PHPStudy 并搭建DVWA靶场
目录 一、PHPStudy 简介 二、DVWA 简介 三、安装 PHPStudy 四:安装 DVWA 一、PHPStudy 简介 phpstudy傻瓜式的一键启动,支持WAMP、WNMP、LAMP、LNMP,一键切换环境(nginxapahce),一键切换PHP版本(5.1-7…...

RoCBert:具有多模态对比预训练的健壮中文BERT
摘要 大规模预训练语言模型在自然语言处理(NLP)任务上取得了最新的最优结果(SOTA)。然而,这些模型容易受到对抗攻击的影响,尤其是对于表意文字语言(如中文)。 在本研究中࿰…...

【C】堆的应用1 -- 堆排序
之前学习了堆,堆的一棵以顺序结构存储的完全二叉树,堆本身又氛围大根堆和小根堆,假设以大根堆为例,由于堆顶部元素是一棵二叉树里面最大的元素,所以如果每次都取堆顶的元素,那么取出的元素就是一个降序排列…...

BGP配置华为——路径优选验证
实验拓扑 实验要求 实现通过修改AS-Path属性来影响路径选择实现通过修改Local_Preference属性来影响路径选择实现通过修改MED属性来影响路径选择实现通过修改preferred-value属性来影响路径选择 实验配置与效果 1.改名与IP配置 2.as300配置OSPF R3已经学到R2和R4的路由 3.…...

【原创】Windows11安装WSL“无法解析服务器的名称或地址”问题解决方法
原因分析 出现这个问题一开始以为WSL设置了某个服务器,但是通过运行 nslookup www.microsoft.com 出现下面的提示 PS C:\Windows\system32> nslookup www.microsoft.com 服务器: UnKnown Address: 2408:8000:XXXX:2b00:8:8:8:8非权威应答: 名称: e13678…...
【CS285】高斯策略对数概率公式的学习笔记
公式介绍 在【CS285】中提到了高斯策略对数概率公式的公式如下: log π θ ( a t ∣ s t ) − 1 2 ∥ f ( s t ) − a t ∥ Σ 2 const \log \pi_{\theta}(\mathbf{a}_t | \mathbf{s}_t) -\frac{1}{2} \left\| f(\mathbf{s}_t) - \mathbf{a}_t \right\|_{\S…...

R与RStudio简介及安装
目录 一、R与RStudio关系 二、R简介 2.1. 发展历史 2.2. R语言特点 三、安装指南 3.1 R安装指南 3.2 R studio安装指南 一、R与RStudio关系 R是统计领域广泛使用的工具,属于GNU系统的一个自由、免费、源代码开放的软件,是 用于统计计算和统计绘图…...

TTL和CMOS的区别【数电速通】
CMOS电平:电压范围在3~15V;常见电压在12V。 TTL电平:电压范围在0~5V,常见都是5V CMOS的特点:电平由电源VDD 决定,而不是外部电源电平。 COMS电路的使用注意事项 我们在使用CMOS…...

Linux红帽:RHCSA认证知识讲解(二)配置网络与登录本地远程Linux主机
Linux红帽:RHCSA认证知识讲解(二)配置网络与登录本地远程Linux主机 前言一、使用命令行(nmcli 命令)配置网络,配置主机名第一步第二步修改主机名称 二、使用图形化界面(nmtui 命令)配…...

Threejs教程一【三要素】
场景 场景是一个容器,用于容纳所有的物体、光源、相机等元素。 // 创建场景 const scene new THREE.Scene(); //修改背景颜色,颜色支持十六进制、rgb、hsl、贴图等 scene.background new THREE.Color(0x000000);相机 相机决定了渲染的结果ÿ…...
3-1 WPS JS宏工作簿的新建与保存(批量新建工作簿)学习笔记
************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…...

明日方舟一键端+单机+联网+安装教程+客户端apk
为了学习和研究软件内含的设计思想和原理,本人花心血和汗水带来了搭建教程!!! 教程不适于服架设,严禁服架设!!!请牢记!!! 教程仅限学习使用&…...

Redis基操
redis 存储在内存中 key-value存储 主要存储热点数据(短时间大量的访客去访问) 启动命令 redis-server.exe redis.windows.conf 客户端链接redis服务器 redis-cli.exe redis-cli.exe -h localhost -p 6379 redis-cli.exe -h localhost -p 6379 -a 123456 退出 exit 命令不区分…...
学习笔记03——《深入理解Java虚拟机(第三版)》类加载机制知识总结与面试核心要点
《深入理解Java虚拟机(第三版)》类加载机制知识总结与面试核心要点 一、章节核心脉络 核心命题:JVM如何将.class文件加载到内存并转换为运行时数据结构? 核心流程:加载 → 验证 → 准备 → 解析 → 初始化 → 使用 →…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...